mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
New API: copy-attributes.
This allows one to copy attributes (like permissions, xattrs, ownership) from a file to another.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
157
fish/test-file-attrs.sh
Executable 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
|
||||
@@ -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.
|
||||
|
||||
@@ -1 +1 @@
|
||||
414
|
||||
415
|
||||
|
||||
Reference in New Issue
Block a user