Hi,
attached there is a prototype of patch for adding a new copy-attributes
command. Such command would allow copy the attributes of a "file" to
another, so for example in guestfish:
copy-attributes foo bar permissions:true xattributes:false
would only copy the permissions of foo to bar, not copying its extended
attributes too.
Just few notes:
- my first daemon command, so possibly I could be missing something
- copy_xattrs is in xattr.c to avoid spreading the usage of xattr API in
many places
- copy_xattrs does a bit of code repetition with other stuff in xattr.c,
but I'm not sure how to avoid it without making the xattr listing code
(getxattrs) a bit more complex that what it is already
Comments?
--
Pino Toscano
diff --git a/daemon/daemon.h b/daemon/daemon.h
index b77d764..6535658 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -231,6 +231,9 @@ extern void journal_finalize (void);
/*-- in proto.c --*/
extern void main_loop (int sock) __attribute__((noreturn));
+/*-- in xattr.c --*/
+extern int copy_xattrs (const char *src, const char *dest);
+
/* ordinary daemon functions use these to indicate errors
* NB: you don't need to prefix the string with the current command,
* it is added automatically by the client-side RPC stubs.
diff --git a/daemon/file.c b/daemon/file.c
index f348f87..fd6da71 100644
--- a/daemon/file.c
+++ b/daemon/file.c
@@ -28,6 +28,7 @@
#include "guestfs_protocol.h"
#include "daemon.h"
#include "actions.h"
+#include "optgroups.h"
GUESTFSD_EXT_CMD(str_file, file);
GUESTFSD_EXT_CMD(str_zcat, zcat);
@@ -584,3 +585,46 @@ do_filesize (const char *path)
return buf.st_size;
}
+
+int
+do_copy_attributes (const char *src, const char *dest, int permissions, int xattributes)
+{
+ int r;
+ struct stat srcstat, deststat;
+
+ CHROOT_IN;
+ r = stat (src, &srcstat);
+ CHROOT_OUT;
+
+ if (r == -1) {
+ reply_with_perror ("stat: %s", src);
+ return -1;
+ }
+
+ CHROOT_IN;
+ r = stat (dest, &deststat);
+ CHROOT_OUT;
+
+ if (r == -1) {
+ reply_with_perror ("stat: %s", dest);
+ return -1;
+ }
+
+ if (permissions && ((srcstat.st_mode & 0777) != (deststat.st_mode & 0777))) {
+ CHROOT_IN;
+ r = chmod (dest, (srcstat.st_mode & 0777));
+ CHROOT_OUT;
+
+ if (r == -1) {
+ reply_with_perror ("chmod: %s", dest);
+ return -1;
+ }
+ }
+
+ if (xattributes && optgroup_linuxxattrs_available ()) {
+ if (!copy_xattrs (src, dest))
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/daemon/xattr.c b/daemon/xattr.c
index af8bfd4..97a94d5 100644
--- a/daemon/xattr.c
+++ b/daemon/xattr.c
@@ -545,8 +545,98 @@ do_lgetxattr (const char *path, const char *name, size_t *size_r)
return buf; /* caller frees */
}
+int
+copy_xattrs (const char *src, const char *dest)
+{
+#if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR) && defined(HAVE_SETXATTR)
+ ssize_t len, vlen, ret;
+ CLEANUP_FREE char *buf = NULL, *attrval = NULL;
+ size_t i, attrval_len = 0;
+
+ CHROOT_IN;
+ len = listxattr (src, NULL, 0);
+ CHROOT_OUT;
+ if (len == -1) {
+ reply_with_perror ("listxattr: %s", src);
+ goto error;
+ }
+
+ buf = malloc (len);
+ if (buf == NULL) {
+ reply_with_perror ("malloc");
+ goto error;
+ }
+
+ CHROOT_IN;
+ len = listxattr (src, buf, len);
+ CHROOT_OUT;
+ if (len == -1) {
+ reply_with_perror ("listxattr: %s", src);
+ goto error;
+ }
+
+ /* What we get from the kernel is a string "foo\0bar\0baz" of length
+ * len.
+ */
+ for (i = 0; i < (size_t) len; i += strlen (&buf[i]) + 1) {
+ CHROOT_IN;
+ vlen = getxattr (src, &buf[i], NULL, 0);
+ CHROOT_OUT;
+ if (vlen == -1) {
+ reply_with_perror ("getxattr: %s, %s", src, &buf[i]);
+ goto error;
+ }
+
+ if (vlen > XATTR_SIZE_MAX) {
+ /* The next call to getxattr will fail anyway, so ... */
+ reply_with_error ("extended attribute is too large");
+ goto error;
+ }
+
+ if (vlen > attrval_len) {
+ char *new = realloc (attrval, vlen);
+ if (new == NULL) {
+ reply_with_perror ("realloc");
+ goto error;
+ }
+ attrval = new;
+ attrval_len = vlen;
+ }
+
+ CHROOT_IN;
+ vlen = getxattr (src, &buf[i], attrval, vlen);
+ CHROOT_OUT;
+ if (vlen == -1) {
+ reply_with_perror ("getxattr: %s, %s", src, &buf[i]);
+ goto error;
+ }
+
+ CHROOT_IN;
+ ret = setxattr (dest, &buf[i], attrval, vlen, 0);
+ CHROOT_OUT;
+ if (vlen == -1) {
+ reply_with_perror ("setxattr: %s, %s", dest, &buf[i]);
+ goto error;
+ }
+ }
+
+ return 1;
+
+ error:
+ return 0;
+#else
+ return 0;
+#endif
+}
+
#else /* no xattr.h */
OPTGROUP_LINUXXATTRS_NOT_AVAILABLE
+int
+copy_xattrs (const char *src, const char *dest)
+{
+ abort ();
+}
+
#endif /* no xattr.h */
diff --git a/fish/Makefile.am b/fish/Makefile.am
index bd0485f..fb0e99e 100644
--- a/fish/Makefile.am
+++ b/fish/Makefile.am
@@ -279,6 +279,7 @@ if ENABLE_APPLIANCE
TESTS += \
test-copy.sh \
test-edit.sh \
+ test-file-attrs.sh \
test-find0.sh \
test-inspect.sh \
test-glob.sh \
diff --git a/fish/test-file-attrs.sh b/fish/test-file-attrs.sh
new file mode 100755
index 0000000..85c6d29
--- /dev/null
+++ b/fish/test-file-attrs.sh
@@ -0,0 +1,118 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2014 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
+# 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.
+
+# Test guestfish file attributes commands (chmod, copy-attributes, etc).
+
+set -e
+export LANG=C
+
+rm -f test.out
+
+$VG ./guestfish > test.out <<EOF
+scratch 50MB
+run
+part-disk /dev/sda mbr
+mkfs ext2 /dev/sda1
+mount /dev/sda1 /
+
+touch /foo
+touch /bar
+chmod 0712 /foo
+stat /foo | grep mode:
+copy-attributes /foo /bar permissions:true
+stat /bar | grep mode:
+EOF
+
+if [ "$(cat test.out)" != "mode: 33226
+mode: 33226" ]; then
+ echo "$0: unexpected output:"
+ cat test.out
+ exit 1
+fi
+
+$VG ./guestfish > test.out <<EOF
+scratch 50MB
+run
+part-disk /dev/sda mbr
+mkfs ext2 /dev/sda1
+mount /dev/sda1 /
+
+touch /foo
+touch /bar
+setxattr user.test foo 3 /foo
+setxattr user.test2 secondtest 10 /foo
+setxattr user.foo another 7 /bar
+lxattrlist / "foo bar"
+copy-attributes /foo /bar xattributes:true
+lxattrlist / "foo bar"
+EOF
+
+if [ "$(cat test.out)" != "[0] = {
+ attrname:
+ attrval: 2\x00
+}
+[1] = {
+ attrname: user.test
+ attrval: foo
+}
+[2] = {
+ attrname: user.test2
+ attrval: secondtest
+}
+[3] = {
+ attrname:
+ attrval: 1\x00
+}
+[4] = {
+ attrname: user.foo
+ attrval: another
+}
+[0] = {
+ attrname:
+ attrval: 2\x00
+}
+[1] = {
+ attrname: user.test
+ attrval: foo
+}
+[2] = {
+ attrname: user.test2
+ attrval: secondtest
+}
+[3] = {
+ attrname:
+ attrval: 3\x00
+}
+[4] = {
+ attrname: user.foo
+ attrval: another
+}
+[5] = {
+ attrname: user.test
+ attrval: foo
+}
+[6] = {
+ attrname: user.test2
+ attrval: secondtest
+}" ]; then
+ echo "$0: unexpected output:"
+ cat test.out
+ exit 1
+fi
+
+rm test.out
diff --git a/generator/actions.ml b/generator/actions.ml
index 9fa7acb..676a3ea 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -11647,6 +11647,28 @@ This function is used internally when setting up the appliance." };
This function is used internally when closing the appliance. Note
it's only called when ./configure --enable-valgrind-daemon is used." };
+ { defaults with
+ name = "copy_attributes";
+ style = RErr, [Pathname "src"; Pathname "dest"], [OBool "permissions"; OBool "xattributes"];
+ proc_nr = Some 415;
+ shortdesc = "copy the attributes of a path (file/directory) to another";
+ longdesc = "\
+Copy the attributes of a path (which can be a file or a directory)
+to another path.
+
+By default B<no> attribute is copied; you have to specify which attributes
+to copy enabling the optional arguments:
+
+=over 4
+
+=item C<permissions>
+
+Copy the UNIX permissions from C<source> to C<destination>.
+
+=item C<xattributes>
+
+Copy the extended attributes from C<source> to C<destination>." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index d1b9f6a..21c8d99 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-414
+415
_______________________________________________
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs