New APIs for reading and writing ext2 file attributes and file generation.

The new APIs are:

  get-e2attrs: List ext2 file attributes of a file.
  set-e2attrs: Set or clear ext2 file attributes of a file.
  get-e2generation: Get ext2 file generation of a file.
  set-e2generation: Set ext2 file generation of a file.

These are implemented using the lsattr and chattr programs from
e2fsprogs.
This commit is contained in:
Richard W.M. Jones
2012-04-13 13:13:50 +01:00
parent 9ccde76f61
commit 8104b2dfab
6 changed files with 392 additions and 6 deletions

2
TODO
View File

@@ -51,8 +51,6 @@ Ideas for extra commands
more mk*temp calls
ext2 properties:
chattr
lsattr
badblocks
debugfs
dumpe2fs

View File

@@ -1,5 +1,5 @@
/* libguestfs - the guestfsd daemon
* Copyright (C) 2009 Red Hat Inc.
* Copyright (C) 2009-2012 Red Hat Inc.
*
* 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
@@ -694,3 +694,195 @@ do_tune2fs (const char *device, /* only required parameter */
free (err);
return 0;
}
static int
compare_chars (const void *vc1, const void *vc2)
{
char c1 = * (char *) vc1;
char c2 = * (char *) vc2;
return c1 - c2;
}
char *
do_get_e2attrs (const char *filename)
{
int r;
char *buf;
char *out, *err;
size_t i, j;
buf = sysroot_path (filename);
if (!buf) {
reply_with_perror ("malloc");
return NULL;
}
r = command (&out, &err, "lsattr", "-d", "--", buf, NULL);
free (buf);
if (r == -1) {
reply_with_error ("%s: %s: %s", "lsattr", filename, err);
free (err);
free (out);
return NULL;
}
free (err);
/* Output looks like:
* -------------e- filename
* Remove the dashes and return everything up to the space.
*/
for (i = j = 0; out[j] != ' '; j++) {
if (out[j] != '-')
out[i++] = out[j];
}
out[i] = '\0';
/* Sort the output, mainly to make testing simpler. */
qsort (out, i, sizeof (char), compare_chars);
return out;
}
/* Takes optional arguments, consult optargs_bitmask. */
int
do_set_e2attrs (const char *filename, const char *attrs, int clear)
{
int r;
char *buf;
char *err;
size_t i, j;
int lowers[26], uppers[26];
char attr_arg[26*2+1+1]; /* '+'/'-' + attrs + trailing '\0' */
if (!(optargs_bitmask & GUESTFS_SET_E2ATTRS_CLEAR_BITMASK))
attr_arg[0] = '+';
else if (!clear)
attr_arg[0] = '+';
else
attr_arg[0] = '-';
j = 1;
/* You can't write "chattr - file", so we have to just return if
* the string is empty.
*/
if (STREQ (attrs, ""))
return 0;
/* Valid attrs are all lower or upper case ASCII letters. Check
* this and that there are no duplicates.
*/
memset (lowers, 0, sizeof lowers);
memset (uppers, 0, sizeof uppers);
for (; *attrs; attrs++) {
/* These are reserved by the chattr program for command line flags. */
if (*attrs == 'R' || *attrs == 'V' || *attrs == 'f' || *attrs == 'v') {
reply_with_error ("bad file attribute '%c'", *attrs);
return -1;
}
else if (*attrs >= 'a' && *attrs <= 'z') {
i = *attrs - 'a';
if (lowers[i] > 0)
goto error_duplicate;
lowers[i]++;
attr_arg[j++] = *attrs;
}
else if (*attrs >= 'A' && *attrs <= 'Z') {
i = *attrs - 'A';
if (uppers[i] > 0) {
error_duplicate:
reply_with_error ("duplicate file attribute '%c'", *attrs);
return -1;
}
uppers[i]++;
attr_arg[j++] = *attrs;
}
else {
reply_with_error ("unknown file attribute '%c'", *attrs);
return -1;
}
}
attr_arg[j] = '\0';
buf = sysroot_path (filename);
if (!buf) {
reply_with_perror ("malloc");
return -1;
}
r = command (NULL, &err, "chattr", attr_arg, "--", buf, NULL);
free (buf);
if (r == -1) {
reply_with_error ("%s: %s: %s", "chattr", filename, err);
free (err);
return -1;
}
free (err);
return 0;
}
int64_t
do_get_e2generation (const char *filename)
{
int r;
char *buf;
char *out, *err;
int64_t ret;
buf = sysroot_path (filename);
if (!buf) {
reply_with_perror ("malloc");
return -1;
}
r = command (&out, &err, "lsattr", "-dv", "--", buf, NULL);
free (buf);
if (r == -1) {
reply_with_error ("%s: %s: %s", "lsattr", filename, err);
free (err);
free (out);
return -1;
}
free (err);
if (sscanf (out, "%" SCNu64, &ret) != 1) {
reply_with_error ("cannot parse output from '%s' command: %s",
"lsattr", out);
free (out);
return -1;
}
free (out);
return ret;
}
int
do_set_e2generation (const char *filename, int64_t generation)
{
int r;
char *buf;
char *err;
char generation_str[64];
buf = sysroot_path (filename);
if (!buf) {
reply_with_perror ("malloc");
return -1;
}
snprintf (generation_str, sizeof generation_str,
"%" PRIu64, (uint64_t) generation);
r = command (NULL, &err, "chattr", "-v", generation_str, "--", buf, NULL);
free (buf);
if (r == -1) {
reply_with_error ("%s: %s: %s", "chattr", filename, err);
free (err);
return -1;
}
free (err);
return 0;
}

View File

@@ -6940,6 +6940,199 @@ For more information on the optional arguments, see L<mkfs.btrfs(8)>.
To create general filesystems, use C<guestfs_mkfs_opts>.");
("get_e2attrs", (RString "attrs", [Pathname "file"], []), 318, [],
[InitScratchFS, Always, TestOutput (
[["touch"; "/e2attrs1"];
["get_e2attrs"; "/e2attrs1"]], "");
InitScratchFS, Always, TestOutput (
[["touch"; "/e2attrs2"];
["set_e2attrs"; "/e2attrs2"; "is"; "false"];
["get_e2attrs"; "/e2attrs2"]], "is");
InitScratchFS, Always, TestOutput (
[["touch"; "/e2attrs3"];
["set_e2attrs"; "/e2attrs3"; "is"; "false"];
["set_e2attrs"; "/e2attrs3"; "i"; "true"];
["get_e2attrs"; "/e2attrs3"]], "s");
InitScratchFS, Always, TestOutput (
[["touch"; "/e2attrs4"];
["set_e2attrs"; "/e2attrs4"; "adst"; "false"];
["set_e2attrs"; "/e2attrs4"; "iS"; "false"];
["set_e2attrs"; "/e2attrs4"; "i"; "true"];
["set_e2attrs"; "/e2attrs4"; "ad"; "true"];
["set_e2attrs"; "/e2attrs4"; ""; "false"];
["set_e2attrs"; "/e2attrs4"; ""; "true"];
["get_e2attrs"; "/e2attrs4"]], "Sst");
InitScratchFS, Always, TestLastFail (
[["touch"; "/e2attrs5"];
["set_e2attrs"; "/e2attrs5"; "R"; "false"]]);
InitScratchFS, Always, TestLastFail (
[["touch"; "/e2attrs6"];
["set_e2attrs"; "/e2attrs6"; "v"; "false"]]);
InitScratchFS, Always, TestLastFail (
[["touch"; "/e2attrs7"];
["set_e2attrs"; "/e2attrs7"; "aa"; "false"]]);
InitScratchFS, Always, TestLastFail (
[["touch"; "/e2attrs8"];
["set_e2attrs"; "/e2attrs8"; "BabcdB"; "false"]])],
"get ext2 file attributes of a file",
"\
This returns the file attributes associated with C<file>.
The attributes are a set of bits associated with each
inode which affect the behaviour of the file. The attributes
are returned as a string of letters (described below). The
string may be empty, indicating that no file attributes are
set for this file.
These attributes are only present when the file is located on
an ext2/3/4 filesystem. Using this call on other filesystem
types will result in an error.
The characters (file attributes) in the returned string are
currently:
=over 4
=item 'A'
When the file is accessed, its atime is not modified.
=item 'a'
The file is append-only.
=item 'c'
The file is compressed on-disk.
=item 'D'
(Directories only.) Changes to this directory are written
synchronously to disk.
=item 'd'
The file is not a candidate for backup (see L<dump(8)>).
=item 'E'
The file has compression errors.
=item 'e'
The file is using extents.
=item 'h'
The file is storing its blocks in units of the filesystem blocksize
instead of sectors.
=item 'I'
(Directories only.) The directory is using hashed trees.
=item 'i'
The file is immutable. It cannot be modified, deleted or renamed.
No link can be created to this file.
=item 'j'
The file is data-journaled.
=item 's'
When the file is deleted, all its blocks will be zeroed.
=item 'S'
Changes to this file are written synchronously to disk.
=item 'T'
(Directories only.) This is a hint to the block allocator
that subdirectories contained in this directory should be
spread across blocks. If not present, the block allocator
will try to group subdirectories together.
=item 't'
For a file, this disables tail-merging.
(Not used by upstream implementations of ext2.)
=item 'u'
When the file is deleted, its blocks will be saved, allowing
the file to be undeleted.
=item 'X'
The raw contents of the compressed file may be accessed.
=item 'Z'
The compressed file is dirty.
=back
More file attributes may be added to this list later. Not all
file attributes may be set for all kinds of files. For
detailed information, consult the L<chattr(1)> man page.
See also C<guestfs_set_e2attrs>.
Don't confuse these attributes with extended attributes
(see C<guestfs_getxattr>).");
("set_e2attrs", (RErr, [Pathname "file"; String "attrs"], [OBool "clear"]), 319, [],
[] (* tested by get_e2attrs *),
"set ext2 file attributes of a file",
"\
This sets or clears the file attributes C<attrs>
associated with the inode C<file>.
C<attrs> is a string of characters representing
file attributes. See C<guestfs_get_e2attrs> for a list of
possible attributes. Not all attributes can be changed.
If optional boolean C<clear> is not present or false, then
the C<attrs> listed are set in the inode.
If C<clear> is true, then the C<attrs> listed are cleared
in the inode.
In both cases, other attributes not present in the C<attrs>
string are left unchanged.
These attributes are only present when the file is located on
an ext2/3/4 filesystem. Using this call on other filesystem
types will result in an error.");
("get_e2generation", (RInt64 "generation", [Pathname "file"], []), 320, [],
[InitScratchFS, Always, TestOutputInt (
[["touch"; "/e2generation"];
["set_e2generation"; "/e2generation"; "123456"];
["get_e2generation"; "/e2generation"]], 123456)],
"get ext2 file generation of a file",
"\
This returns the ext2 file generation of a file. The generation
(which used to be called the \"version\") is a number associated
with an inode. This is most commonly used by NFS servers.
The generation is only present when the file is located on
an ext2/3/4 filesystem. Using this call on other filesystem
types will result in an error.
See C<guestfs_set_e2generation>.");
("set_e2generation", (RErr, [Pathname "file"; Int64 "generation"], []), 321, [],
[], (* tested by get_e2generation *)
"set ext2 file generation of a file",
"\
This sets the ext2 file generation of a file.
See C<guestfs_get_e2generation>.");
]
let all_functions = non_daemon_functions @ daemon_functions

View File

@@ -58,7 +58,8 @@ guestfs_gobject_headers=\
guestfs-gobject-optargs-e2fsck.h \
guestfs-gobject-optargs-ntfsfix.h \
guestfs-gobject-optargs-ntfsclone_out.h \
guestfs-gobject-optargs-mkfs_btrfs.h
guestfs-gobject-optargs-mkfs_btrfs.h \
guestfs-gobject-optargs-set_e2attrs.h
guestfs_gobject_sources=\
guestfs-gobject-session.c \
@@ -98,4 +99,5 @@ guestfs_gobject_sources=\
guestfs-gobject-optargs-e2fsck.c \
guestfs-gobject-optargs-ntfsfix.c \
guestfs-gobject-optargs-ntfsclone_out.c \
guestfs-gobject-optargs-mkfs_btrfs.c
guestfs-gobject-optargs-mkfs_btrfs.c \
guestfs-gobject-optargs-set_e2attrs.c

View File

@@ -149,6 +149,7 @@ gobject/guestfs-gobject-optargs-mount_local.c
gobject/guestfs-gobject-optargs-ntfsclone_out.c
gobject/guestfs-gobject-optargs-ntfsfix.c
gobject/guestfs-gobject-optargs-ntfsresize_opts.c
gobject/guestfs-gobject-optargs-set_e2attrs.c
gobject/guestfs-gobject-optargs-test0.c
gobject/guestfs-gobject-optargs-tune2fs.c
gobject/guestfs-gobject-optargs-umount_local.c

View File

@@ -1 +1 @@
317
321