On Friday 10 January 2014 13:33:38 Richard W.M. Jones wrote:
> On Fri, Jan 10, 2014 at 02:17:48PM +0100, Pino Toscano wrote:
> > > This code looks as if it will copy the xattrs, but it won't
> > >
> > > remove any which don't exist in the source. eg:
> > > source xattrs before:
> > > user.foo = 1
> > >
> > > dest xattrs before:
> > > user.bar = 2
> > >
> > > dest xattrs after:
> > > user.foo = 1
> > > user.bar = 2
> > >
> > > That may or may not be what we want, but I would say it's a bit
> > > unexpected.
> >
> > Yes, the current behaviour is done on purpose; my thought that,
> > given
> > the command is "copy attributes", it would just copy what specified
> > from the source to the destination.
> >
> > I see reasons for both the behaviours, so I'm not totally sure which
> > one pick.
>
> On the basis that most users will be creating a new file (which will
> have no xattrs except in some very odd corner cases), just leave your
> implementation for now, but don't specify it in the documentation so
> we could change it later.
After all, the documentation says that it just copies the xattrs from
the source to the destination, but it does not explicitly mention what
is done with the xattrs in the destination not in the source ... :-)
On Friday 10 January 2014 13:36:06 Richard W.M. Jones wrote:
> On Fri, Jan 10, 2014 at 01:33:38PM +0000, Richard W.M. Jones wrote:
> > The API is now pretty confusing. Each OBool flag is really a
> > tristate. It can either be "true", "false" or "not specified".
I see, I did not pay much attention to the use of optargs_bitmask
outside the auto-generated RPC stuff the daemon code.
> > Therefore I think it should be:
> > xattributes:true # copies only xattrs and nothing else
> > all:true # copies everything
> > all:true xattributes:false # copies everything except xattrs
> >
> > In other words, 'all' changes the default (ie. "not specified")
> > state
> > of the other flags.
Given the above, this indeed becomes straightforward to have.
> > To be clearer, the four OBool parameters would be:
> > [OBool "all"; OBool "mode"; OBool "ownership"; OBool
> > "xattributes"]
>
> So looking at your v2 patch a bit more, I think this is what you
> already did, except that "skipmode" is backwards from the other flags.
> I think we're in agreement, except I think "skipmode" should just
> become "mode" and not have negated meaning compared to the other
> flags.
OK, I will turn it back as it was before (into "mode"), but making use
of the tristate information to have it true by default.
> We're allowed to extend the API later by adding optional flags (see
> "Note about extending functions" in generator/README for the
> complicated rules about extending APIs while preserving binary
> compatibility).
Yes, I read it earlier, that's why I'm not that concerned about adding
all the potential attributes now.
Attached there is the v3 of the patch.
--
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..34ec95a 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,79 @@ do_filesize (const char *path)
return buf.st_size;
}
+
+int
+do_copy_attributes (const char *src, const char *dest, int all, int mode, int xattributes, int ownership)
+{
+ int r;
+ struct stat srcstat, deststat;
+
+ static const unsigned int file_mask = 07777;
+
+ /* If it was specified to copy everything, manually enable all the flags
+ * not manually specified to avoid checking for flag || all everytime.
+ */
+ if (all) {
+ if (!(optargs_bitmask & GUESTFS_COPY_ATTRIBUTES_MODE_BITMASK))
+ mode = 1;
+ if (!(optargs_bitmask & GUESTFS_COPY_ATTRIBUTES_XATTRIBUTES_BITMASK))
+ xattributes = 1;
+ if (!(optargs_bitmask & GUESTFS_COPY_ATTRIBUTES_OWNERSHIP_BITMASK))
+ ownership = 1;
+ } else if ((!(optargs_bitmask & GUESTFS_COPY_ATTRIBUTES_ALL_BITMASK)) &&
+ (!(optargs_bitmask & GUESTFS_COPY_ATTRIBUTES_MODE_BITMASK))) {
+ /* Neither "all" nor "mode" were specified, so make "mode" on by default.
+ */
+ mode = 1;
+ }
+
+ 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 (mode &&
+ ((srcstat.st_mode & file_mask) != (deststat.st_mode & file_mask))) {
+ CHROOT_IN;
+ r = chmod (dest, (srcstat.st_mode & file_mask));
+ CHROOT_OUT;
+
+ if (r == -1) {
+ reply_with_perror ("chmod: %s", dest);
+ return -1;
+ }
+ }
+
+ if (ownership &&
+ (srcstat.st_uid != deststat.st_uid || srcstat.st_gid != deststat.st_gid)) {
+ CHROOT_IN;
+ r = chown (dest, srcstat.st_uid, srcstat.st_gid);
+ CHROOT_OUT;
+
+ if (r == -1) {
+ reply_with_perror ("chown: %s", dest);
+ return -1;
+ }
+ }
+
+ if (xattributes && optgroup_linuxxattrs_available ()) {
+ if (!copy_xattrs (src, dest))
+ /* copy_xattrs replies with an error already. */
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/daemon/xattr.c b/daemon/xattr.c
index e01e9e2..08c09e1 100644
--- a/daemon/xattr.c
+++ b/daemon/xattr.c
@@ -542,8 +542,77 @@ 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)
+{
+ ssize_t len, vlen, ret;
+ CLEANUP_FREE char *buf = NULL, *attrval = NULL;
+ size_t i, attrval_len = 0;
+
+ buf = _listxattrs (src, listxattr, &len);
+ if (buf == NULL)
+ /* _listxattrs issues reply_with_perror already. */
+ 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 /* no HAVE_LINUX_XATTRS */
OPTGROUP_LINUXXATTRS_NOT_AVAILABLE
+int
+copy_xattrs (const char *src, const char *dest)
+{
+ abort ();
+}
+
#endif /* no HAVE_LINUX_XATTRS */
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..b85a35c
--- /dev/null
+++ b/fish/test-file-attrs.sh
@@ -0,0 +1,157 @@
+#!/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
+stat /bar | grep mode:
+
+echo -----
+
+stat /foo | grep uid:
+stat /foo | grep gid:
+chown 10 11 /foo
+stat /foo | grep uid:
+stat /foo | grep gid:
+stat /bar | grep uid:
+stat /bar | grep gid:
+copy-attributes /foo /bar ownership:true
+stat /bar | grep uid:
+stat /bar | grep gid:
+
+echo -----
+
+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"
+
+echo -----
+
+touch /new
+chmod 0111 /new
+copy-attributes /foo /new all:true mode:false
+stat /new | grep mode:
+stat /new | grep uid:
+stat /new | grep gid:
+lxattrlist / new
+copy-attributes /foo /new mode:true
+stat /new | grep mode:
+EOF
+
+if [ "$(cat test.out)" != "mode: 33226
+mode: 33226
+-----
+uid: 0
+gid: 0
+uid: 10
+gid: 11
+uid: 0
+gid: 0
+uid: 10
+gid: 11
+-----
+[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
+}
+-----
+mode: 32841
+uid: 10
+gid: 11
+[0] = {
+ attrname:
+ attrval: 2\x00
+}
+[1] = {
+ attrname: user.test
+ attrval: foo
+}
+[2] = {
+ attrname: user.test2
+ attrval: secondtest
+}
+mode: 33226" ]; 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..5139f22 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -11647,6 +11647,44 @@ 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 "all"; OBool "mode"; OBool "xattributes"; OBool "ownership"];
+ 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 C<mode> is assumed if not explicitly specified, so set it
+(or C<all>) as false to not copy the file mode.
+
+The optional arguments specify which attributes can be copied:
+
+=over 4
+
+=item C<mode>
+
+Copy part of the file mode from C<source> to C<destination>. Only the
+UNIX permissions and the sticky/setuid/setgid bits can be copied.
+
+=item C<xattributes>
+
+Copy the Linux extended attributes (xattrs) from C<source> to C<destination>.
+This flag does nothing if the I<linuxxattrs> feature is not available
+(see C<guestfs_feature_available>).
+
+=item C<ownership>
+
+Copy the owner uid and the group gid of C<source> to C<destination>.
+
+=item C<all>
+
+Copy B<all> the attributes from C<source> to C<destination>. Enabling it
+enables all the other flags, if they are not specified already.
+
+=back" };
+
]
(* 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