summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-04-13 13:13:50 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-04-13 15:44:17 +0100
commit8104b2dfab32aea972ecfc4e89bf350b092e1952 (patch)
treee451b1c6f1292466167a00577e3824fb422ebfc2
parent9ccde76f611bf4658180717a41544350b5b4632a (diff)
downloadlibguestfs-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--TODO2
-rw-r--r--daemon/ext2.c194
-rw-r--r--generator/generator_actions.ml193
-rw-r--r--gobject/Makefile.inc6
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/MAX_PROC_NR2
6 files changed, 392 insertions, 6 deletions
diff --git a/TODO b/TODO
index 571c51b7..43d5e621 100644
--- a/TODO
+++ b/TODO
@@ -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