[Libguestfs] [PATCH] New API: copy-attributes.
Richard W.M. Jones
rjones at redhat.com
Mon Jan 13 13:49:02 UTC 2014
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#)
More information about the Libguestfs
mailing list