New API: copy-attributes.

This allows one to copy attributes (like permissions, xattrs,
ownership) from a file to another.
This commit is contained in:
Pino Toscano
2014-01-13 14:41:28 +01:00
parent 418c064bc1
commit efb5f18415
7 changed files with 341 additions and 1 deletions

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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 \

157
fish/test-file-attrs.sh Executable file
View File

@@ -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

View File

@@ -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.

View File

@@ -1 +1 @@
414
415