New API: vfs_minimum_size

This call provides the way to get minimum size of filesystem.
This is needed for shrinking. The return units are bytes.
This commit is contained in:
Maxim Perevedentsev
2015-10-20 18:45:55 +03:00
committed by Richard W.M. Jones
parent e9b32e1bad
commit b8d4ca686b
7 changed files with 156 additions and 1 deletions

View File

@@ -116,6 +116,7 @@ guestfsd_SOURCES = \
findfs.c \
fill.c \
find.c \
fs-min-size.c \
fsck.c \
fstrim.c \
glob.c \

View File

@@ -283,6 +283,7 @@ extern int btrfs_set_uuid_random (const char *device);
/*-- in ntfs.c --*/
extern char *ntfs_get_label (const char *device);
extern int ntfs_set_label (const char *device, const char *label);
extern int64_t ntfs_minimum_size (const char *device);
/*-- in swap.c --*/
extern int swap_set_uuid (const char *device, const char *uuid);

46
daemon/fs-min-size.c Normal file
View File

@@ -0,0 +1,46 @@
/* libguestfs - the guestfsd daemon
* Copyright (C) 2015 Maxim Perevedentsev mperevedentsev@virtuozzo.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "daemon.h"
#include "actions.h"
int64_t
do_vfs_minimum_size (const mountable_t *mountable)
{
int64_t r;
/* How we set the label depends on the filesystem type. */
CLEANUP_FREE char *vfs_type = do_vfs_type (mountable);
if (vfs_type == NULL)
return -1;
else if (STREQ (vfs_type, "ntfs"))
r = ntfs_minimum_size (mountable->device);
else
NOT_SUPPORTED (-1, "don't know how to get minimum size of '%s' filesystems",
vfs_type);
return r;
}

View File

@@ -27,6 +27,7 @@
#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
#include "xstrtol.h"
#define MAX_ARGS 64
@@ -153,6 +154,92 @@ do_ntfsresize_size (const char *device, int64_t size)
return do_ntfsresize (device, size, 0);
}
int64_t
ntfs_minimum_size (const char *device)
{
CLEANUP_FREE char *err = NULL, *out = NULL;
CLEANUP_FREE_STRING_LIST char **lines = NULL;
int r;
size_t i;
int64_t volume_size = 0;
const char *size_pattern = "You might resize at ",
*full_pattern = "Volume is full",
*cluster_size_pattern = "Cluster size",
*volume_size_pattern = "Current volume size:";
int is_full = 0;
int32_t cluster_size = 0;
/* FS may be marked for check, so force ntfsresize */
r = command (&out, &err, str_ntfsresize, "--info", "-ff", device, NULL);
lines = split_lines (out);
if (lines == NULL)
return -1;
if (verbose) {
for (i = 0; lines[i] != NULL; ++i)
fprintf (stderr, "ntfs_minimum_size: lines[%zu] = \"%s\"\n", i, lines[i]);
}
#if __WORDSIZE == 64
#define XSTRTOD64 xstrtol
#else
#define XSTRTOD64 xstrtoll
#endif
if (r == -1) {
/* If volume is full, ntfsresize returns error. */
for (i = 0; lines[i] != NULL; ++i) {
if (strstr (lines[i], full_pattern))
is_full = 1;
else if (STRPREFIX (lines[i], cluster_size_pattern)) {
if (sscanf (lines[i] + strlen (cluster_size_pattern),
"%*[ ]:%" SCNd32, &cluster_size) != 1) {
reply_with_error ("cannot parse cluster size");
return -1;
}
}
else if (STRPREFIX (lines[i], volume_size_pattern)) {
if (XSTRTOD64 (lines[i] + strlen (volume_size_pattern),
NULL, 20, &volume_size, NULL) != LONGINT_OK) {
reply_with_error ("cannot parse volume size");
return -1;
}
}
}
if (is_full) {
if (cluster_size == 0) {
reply_with_error ("bad cluster size");
return -1;
}
/* In case of a full filesystem, we estimate minimum size
* as volume size rounded up to cluster size.
*/
return (volume_size + cluster_size - 1) / cluster_size * cluster_size;
}
reply_with_error ("%s", err);
return -1;
}
for (i = 0; lines[i] != NULL; ++i) {
if (STRPREFIX (lines[i], size_pattern)) {
int64_t ret;
if (XSTRTOD64 (lines[i] + strlen (size_pattern),
NULL, 20, &ret, NULL) != LONGINT_OK) {
reply_with_error ("cannot parse minimum size");
return -1;
}
return ret;
}
}
#undef XSTRTOD64
reply_with_error ("minimum size not found. Check output format:\n%s", out);
return -1;
}
/* Takes optional arguments, consult optargs_bitmask. */
int
do_ntfsfix (const char *device, int clearbadsectors)

View File

@@ -12765,6 +12765,25 @@ Get the estimated minimum filesystem size of an ext2/3/4 filesystem in blocks.
See also L<resize2fs(8)>." };
{ defaults with
name = "vfs_minimum_size"; added = (1, 31, 18);
style = RInt64 "sizeinbytes", [Mountable "mountable"], [];
proc_nr = Some 458;
tests = [
InitPartition, IfAvailable "ntfsprogs", TestRun(
[["mkfs"; "ntfs"; "/dev/sda1"; ""; "NOARG"; ""; ""; "NOARG"];
["vfs_minimum_size"; "/dev/sda1"]]), [];
];
shortdesc = "get minimum filesystem size";
longdesc = "\
Get the minimum size of filesystem in bytes.
This is the minimum possible size for filesystem shrinking.
If getting minimum size of specified filesystem is not supported,
this will fail and set errno as ENOTSUP.
See also L<ntfsresize(8)>." };
]
(* Non-API meta-commands available only in guestfish.

View File

@@ -49,6 +49,7 @@ daemon/file.c
daemon/fill.c
daemon/find.c
daemon/findfs.c
daemon/fs-min-size.c
daemon/fsck.c
daemon/fstrim.c
daemon/glob.c

View File

@@ -1 +1 @@
457
458