On Mon, Jan 13, 2014 at 02:45:08PM +0100, Pino Toscano wrote: > This allows one to copy attributes (like permissions, xattrs, > ownership) from a file to another. > --- > daemon/daemon.h | 3 + > daemon/file.c | 72 ++++++++++++++++++++++ > daemon/xattr.c | 69 +++++++++++++++++++++ > fish/Makefile.am | 1 + > fish/test-file-attrs.sh | 157 > ++++++++++++++++++++++++++++++++++++++++++++++++ > generator/actions.ml | 38 ++++++++++++ > src/MAX_PROC_NR | 2 +- > 7 files changed, 341 insertions(+), 1 deletion(-) > create mode 100755 fish/test-file-attrs.sh > > 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..856ab5f 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,74 @@ 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; > + } > + > + 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 ebacc02..abed5ff 100644 > --- a/daemon/xattr.c > +++ b/daemon/xattr.c > @@ -541,8 +541,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, attrval_len = 0; > + CLEANUP_FREE char *buf = NULL, *attrval = NULL; > + size_t i; > + > + 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 (ret == -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..78bd817 > --- /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 mode:true > +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..b4b746f 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<no> attribute is copied, so make sure to specify any > +(or C<all> to copy everything). > + > +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
ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs