diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-04-13 13:13:50 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-04-13 15:44:17 +0100 |
commit | 8104b2dfab32aea972ecfc4e89bf350b092e1952 (patch) | |
tree | e451b1c6f1292466167a00577e3824fb422ebfc2 | |
parent | 9ccde76f611bf4658180717a41544350b5b4632a (diff) | |
download | libguestfs-8104b2dfab32aea972ecfc4e89bf350b092e1952.tar.gz libguestfs-8104b2dfab32aea972ecfc4e89bf350b092e1952.tar.xz libguestfs-8104b2dfab32aea972ecfc4e89bf350b092e1952.zip |
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.
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | daemon/ext2.c | 194 | ||||
-rw-r--r-- | generator/generator_actions.ml | 193 | ||||
-rw-r--r-- | gobject/Makefile.inc | 6 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | src/MAX_PROC_NR | 2 |
6 files changed, 392 insertions, 6 deletions
@@ -51,8 +51,6 @@ Ideas for extra commands more mk*temp calls ext2 properties: - chattr - lsattr badblocks debugfs dumpe2fs diff --git a/daemon/ext2.c b/daemon/ext2.c index 99d45743..68247523 100644 --- a/daemon/ext2.c +++ b/daemon/ext2.c @@ -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; +} diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 4c331af3..5bdc063d 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -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 diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index 6bbe6887..ac65cd37 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -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 diff --git a/po/POTFILES.in b/po/POTFILES.in index 838ebd2a..34064c20 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 4dab36bb..3ae0b938 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -317 +321 |