Re: [Libguestfs] RFC: copy-attributes command

2014-01-13 Thread Pino Toscano
On Friday 10 January 2014 16:53:32 Richard W.M. Jones wrote:
 On Fri, Jan 10, 2014 at 05:36:39PM +0100, Pino Toscano wrote:
 [..]
 
 This still isn't quite what I meant.  My meaning was that mode
 would be disabled by default (unless all:true).

OK.

 How about:
 
 int copy_mode, copy_xattributes, copy_ownership;
 
 /* Set defaults. */
 if (all)
   copy_mode = copy_xattributes = copy_ownership = 1;
 else
   copy_mode = copy_xattributes = copy_ownership = 0;
 
 /* If set in the original struct, copy those settings overriding
  * the defaults.
  */
 if ((optargs_bitmask  GUESTFS_COPY_ATTRIBUTES_MODE_BITMASK))
   copy_mode = mode;
 if ((optargs_bitmask  GUESTFS_COPY_ATTRIBUTES_XATTRIBUTES_BITMASK))
   copy_xattributes = xattributes;
 if ((optargs_bitmask  GUESTFS_COPY_ATTRIBUTES_OWNERSHIP_BITMASK))
   copy_ownership = ownership;

Isn't this doing basically the same of the snippet I used (the «if (all) 
{ ... }» one), short of the part that enables mode if neither all nor 
mode were specified?

-- 
Pino Toscano

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


Re: [Libguestfs] RFC: copy-attributes command

2014-01-13 Thread Richard W.M. Jones
On Mon, Jan 13, 2014 at 12:54:36PM +0100, Pino Toscano wrote:
 On Friday 10 January 2014 16:53:32 Richard W.M. Jones wrote:
  On Fri, Jan 10, 2014 at 05:36:39PM +0100, Pino Toscano wrote:
  [..]
  
  This still isn't quite what I meant.  My meaning was that mode
  would be disabled by default (unless all:true).
 
 OK.
 
  How about:
  
  int copy_mode, copy_xattributes, copy_ownership;
  
  /* Set defaults. */
  if (all)
copy_mode = copy_xattributes = copy_ownership = 1;
  else
copy_mode = copy_xattributes = copy_ownership = 0;
  
  /* If set in the original struct, copy those settings overriding
   * the defaults.
   */
  if ((optargs_bitmask  GUESTFS_COPY_ATTRIBUTES_MODE_BITMASK))
copy_mode = mode;
  if ((optargs_bitmask  GUESTFS_COPY_ATTRIBUTES_XATTRIBUTES_BITMASK))
copy_xattributes = xattributes;
  if ((optargs_bitmask  GUESTFS_COPY_ATTRIBUTES_OWNERSHIP_BITMASK))
copy_ownership = ownership;
 
 Isn't this doing basically the same of the snippet I used (the «if (all) 
 { ... }» one), short of the part that enables mode if neither all nor 
 mode were specified?

Probably.  This way was just easier for me to understand :-)

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine.  Supports Linux and Windows.
http://people.redhat.com/~rjones/virt-df/

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


Re: [Libguestfs] RFC: copy-attributes command

2014-01-10 Thread Pino Toscano
On Tuesday 07 January 2014 21:04:36 Richard W.M. Jones wrote:
 On Tue, Jan 07, 2014 at 04:06:43PM +0100, Pino Toscano wrote:
  Hi,
  
  attached there is a prototype of patch for adding a new
  copy-attributes command. Such command would allow copy the
  attributes of a file to 
  another, so for example in guestfish:
copy-attributes foo bar permissions:true xattributes:false
  
  would only copy the permissions of foo to bar, not copying its
  extended attributes too.
 
 I think the general idea of the new API is fine.
 
 More comments about the code below.
 
  Just few notes:
  - my first daemon command, so possibly I could be missing something
  - copy_xattrs is in xattr.c to avoid spreading the usage of xattr
  API in 
many places
  
  - copy_xattrs does a bit of code repetition with other stuff in
  xattr.c, 
but I'm not sure how to avoid it without making the xattr listing
code (getxattrs) a bit more complex that what it is already
  
  Comments?
  
  
  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..fd6da71 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,46 @@ do_filesize (const char *path)
  
 return buf.st_size;
   
   }
  
  +
  +int
  +do_copy_attributes (const char *src, const char *dest, int
  permissions, int xattributes) +{
  +  int r;
  +  struct stat srcstat, deststat;
  +
  +  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 (permissions  ((srcstat.st_mode  0777) != (deststat.st_mode
   0777))) { +CHROOT_IN;
  +r = chmod (dest, (srcstat.st_mode  0777));
 
 I suspect you want 0 in order to copy sticky/setuid/setgid bits.
 Perhaps those should be a separate flag, but we definitely want to
 copy them!

Right, fixed to be part of the permissions (or mode actually, see 
below).

  +  ssize_t len, vlen, ret;
  +  CLEANUP_FREE char *buf = NULL, *attrval = NULL;
  +  size_t i, attrval_len = 0;
  +
  +  CHROOT_IN;
  +  len = listxattr (src, NULL, 0);
  +  CHROOT_OUT;
  +  if (len == -1) {
  +reply_with_perror (listxattr: %s, src);
  +goto error;
  +  }
  +
  +  buf = malloc (len);
  +  if (buf == NULL) {
  +reply_with_perror (malloc);
  +goto error;
  +  }
  +
  +  CHROOT_IN;
  +  len = listxattr (src, buf, len);
  +  CHROOT_OUT;
  +  if (len == -1) {
  +reply_with_perror (listxattr: %s, src);
  +goto error;
  +  }

This two-pass snippet to do (l)listxattr is already elsewhere in 
xattr.c, I will move it to an own function.

  +  /* 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;
  +}
  +  }
 
 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
 

Re: [Libguestfs] RFC: copy-attributes command

2014-01-10 Thread Richard W.M. Jones
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.

  - Should it default to copying attributes?
 
 You've convinced me, so I've turned the permissions flag into 
 skipmode, so specifying nothing now copies the file mode (so 
 permissions + bits).
 
  The common use case (for virt-edit) is: I want this other file which
  is identical to this original file, except in name and content.  That
  is (I think) an argument for copying everything by default.
 
 I've added a all argument which would enable every change, overriding 
 even mode:false.

The API is now pretty confusing.  Each OBool flag is really a
tristate.  It can either be true, false or not specified.

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.

To be clearer, the four OBool parameters would be:

  [OBool all; OBool mode; OBool ownership; OBool xattributes]

  I would have thought owner uid and group gid should be copied.
 
 Oh true, forgot about them; added a new ownership argument.
 
  - Is there anything else which is useful to copy?
 
 Maybe there's also copying atime/mtime too; worth having a single 
 argument (time) for both, or two separate?

For virt-edit, I would _not_ want it to copy the old time(s).  The
time would be updated.

But I guess there's a use for copying the time(s), so this could be
another flag.

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

 +=over 4
 +
 +=item Cxattributes
 +
 +Copy the Linux extended attributes (xattrs) from Csource to Cdestination.
 +This flag does nothing if the Ilinuxxattrs feature is not available
 +(see Cguestfs_feature_available).
 +
 +=item Call

^ Typo in this line.

 +Copy the owner uid and the group gid of Csource to Cdestination.
 +
 +=item Call
 +
 +Copy Ball the attributes from Csource to Cdestination.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine.  Supports Linux and Windows.
http://people.redhat.com/~rjones/virt-df/

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


Re: [Libguestfs] RFC: copy-attributes command

2014-01-10 Thread Richard W.M. Jones
On Fri, Jan 10, 2014 at 01:33:38PM +, 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.
 
 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.
 
 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.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://libguestfs.org

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


Re: [Libguestfs] RFC: copy-attributes command

2014-01-10 Thread Pino Toscano
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 +, 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 Toscanodiff --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 = 0;
+
+  /* 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 
+ 

Re: [Libguestfs] RFC: copy-attributes command

2014-01-10 Thread Richard W.M. Jones
On Fri, Jan 10, 2014 at 05:36:39PM +0100, Pino Toscano wrote:
[..]

This still isn't quite what I meant.  My meaning was that mode
would be disabled by default (unless all:true).

How about:

int copy_mode, copy_xattributes, copy_ownership;

/* Set defaults. */
if (all)
  copy_mode = copy_xattributes = copy_ownership = 1;
else
  copy_mode = copy_xattributes = copy_ownership = 0;

/* If set in the original struct, copy those settings overriding
 * the defaults.
 */
if ((optargs_bitmask  GUESTFS_COPY_ATTRIBUTES_MODE_BITMASK))
  copy_mode = mode;
if ((optargs_bitmask  GUESTFS_COPY_ATTRIBUTES_XATTRIBUTES_BITMASK))
  copy_xattributes = xattributes;
if ((optargs_bitmask  GUESTFS_COPY_ATTRIBUTES_OWNERSHIP_BITMASK))
  copy_ownership = ownership;

if (!copy_mode  !copy_xattributes  !copy_ownership) {
  /* Short-circuit the code, but this *isn't* an error. */
  return 0;
}

[...]

if (copy_mode)
  // chmod
etc.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://libguestfs.org

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


Re: [Libguestfs] RFC: copy-attributes command

2014-01-09 Thread Pino Toscano
On Tuesday 07 January 2014 21:04:36 Richard W.M. Jones wrote:
 On Tue, Jan 07, 2014 at 04:06:43PM +0100, Pino Toscano wrote:
  diff --git a/daemon/xattr.c b/daemon/xattr.c
  index af8bfd4..97a94d5 100644
  --- a/daemon/xattr.c
  +++ b/daemon/xattr.c
  @@ -545,8 +545,98 @@ 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)
  +{
  +#if defined(HAVE_LISTXATTR)  defined(HAVE_GETXATTR) 
  defined(HAVE_SETXATTR)
 I wonder if there are any platforms that lack one of listxattr,
 getxattr and setxattr, but at the same time have one of these calls.
 The xattr code (in general) is incredibly complex because of all these
 tests.
 
 I guess Mac OS X probably has none of them, and RHEL 5 / Ubuntu 10.10
 probably had only some of them.

At least in the gnu/stubs-$bits.h of RHEL 5 they are not declared as 
__stub_*, so they should be implemented (and being Linux, it means that 
most probably there are the right syscalls for them).
So I would not think the change proposed below (and implemented) would 
cause regressions in such old Linux systems.

 We don't care about RHEL 5 since it
 now has its own branch (oldlinux), so the code might be made simpler
 by an accompanying patch which reduces all of the HAVE_*XATTR* macros
 down to a single one (HAVE_LINUX_XATTRS).

Sounds reasonable; attached a patch for it.

-- 
Pino ToscanoFrom fc4dd8cab10b1c3571c49c0ed8bd3de29e98bd6c Mon Sep 17 00:00:00 2001
From: Pino Toscano ptosc...@redhat.com
Date: Thu, 9 Jan 2014 17:21:31 +0100
Subject: [PATCH] daemon: xattr: simplify the enabling of the linuxxattrs
 features

Instead of enable them when having one of the two headers for it but
still checking for the HAVE_* availability of each *xattr() function
used, just enable the linuxxattrs as a whole when having any of the
needed headers (like before) and all the needed functions.

This might cause the linuxxattrs to not be available anymore on systems
without the whole set of *xattr() functions implemented, but OTOH it
simplifies the xattr.c implementations.
---
 daemon/xattr.c | 49 +++--
 1 file changed, 11 insertions(+), 38 deletions(-)

diff --git a/daemon/xattr.c b/daemon/xattr.c
index af8bfd4..b84cf3d 100644
--- a/daemon/xattr.c
+++ b/daemon/xattr.c
@@ -27,7 +27,15 @@
 #include actions.h
 #include optgroups.h
 
-#if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
+#if (defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H))  \
+defined(HAVE_LISTXATTR)  defined(HAVE_LLISTXATTR)  \
+defined(HAVE_GETXATTR)  defined(HAVE_LGETXATTR)  \
+defined(HAVE_REMOVEXATTR)  defined(HAVE_LREMOVEXATTR)  \
+defined(HAVE_SETXATTR)  defined(HAVE_LSETXATTR)
+# define HAVE_LINUX_XATTRS
+#endif
+
+#ifdef HAVE_LINUX_XATTRS
 
 # ifdef HAVE_ATTR_XATTR_H
 #  include attr/xattr.h
@@ -50,67 +58,37 @@ static int _removexattr (const char *xattr, const char *path, int (*removexattr)
 guestfs_int_xattr_list *
 do_getxattrs (const char *path)
 {
-#if defined(HAVE_LISTXATTR)  defined(HAVE_GETXATTR)
   return getxattrs (path, listxattr, getxattr);
-#else
-  reply_with_error (no support for listxattr and getxattr);
-  return NULL;
-#endif
 }
 
 guestfs_int_xattr_list *
 do_lgetxattrs (const char *path)
 {
-#if defined(HAVE_LLISTXATTR)  defined(HAVE_LGETXATTR)
   return getxattrs (path, llistxattr, lgetxattr);
-#else
-  reply_with_error (no support for llistxattr and lgetxattr);
-  return NULL;
-#endif
 }
 
 int
 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
 {
-#if defined(HAVE_SETXATTR)
   return _setxattr (xattr, val, vallen, path, setxattr);
-#else
-  reply_with_error (no support for setxattr);
-  return -1;
-#endif
 }
 
 int
 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
 {
-#if defined(HAVE_LSETXATTR)
   return _setxattr (xattr, val, vallen, path, lsetxattr);
-#else
-  reply_with_error (no support for lsetxattr);
-  return -1;
-#endif
 }
 
 int
 do_removexattr (const char *xattr, const char *path)
 {
-#if defined(HAVE_REMOVEXATTR)
   return _removexattr (xattr, path, removexattr);
-#else
-  reply_with_error (no support for removexattr);
-  return -1;
-#endif
 }
 
 int
 do_lremovexattr (const char *xattr, const char *path)
 {
-#if defined(HAVE_LREMOVEXATTR)
   return _removexattr (xattr, path, lremovexattr);
-#else
-  reply_with_error (no support for lremovexattr);
-  return -1;
-#endif
 }
 
 static int
@@ -277,7 +255,6 @@ _removexattr (const char *xattr, const char *path,
 guestfs_int_xattr_list *
 do_internal_lxattrlist (const char *path, char *const *names)
 {
-#if defined(HAVE_LLISTXATTR)  defined(HAVE_LGETXATTR)
   guestfs_int_xattr_list *ret = NULL;
   size_t i, j;
   size_t k, m, nr_attrs;
@@ -443,10 +420,6 @@ do_internal_lxattrlist (const char *path, char *const *names)
 free (ret);
   }
   return NULL;
-#else
-  reply_with_error (no support for 

Re: [Libguestfs] RFC: copy-attributes command

2014-01-07 Thread Richard W.M. Jones
On Tue, Jan 07, 2014 at 04:06:43PM +0100, Pino Toscano wrote:
 Hi,
 
 attached there is a prototype of patch for adding a new copy-attributes 
 command. Such command would allow copy the attributes of a file to 
 another, so for example in guestfish:
   copy-attributes foo bar permissions:true xattributes:false
 would only copy the permissions of foo to bar, not copying its extended 
 attributes too.

I think the general idea of the new API is fine.

More comments about the code below.

 Just few notes:
 - my first daemon command, so possibly I could be missing something
 - copy_xattrs is in xattr.c to avoid spreading the usage of xattr API in
   many places
 - copy_xattrs does a bit of code repetition with other stuff in xattr.c,
   but I'm not sure how to avoid it without making the xattr listing code
   (getxattrs) a bit more complex that what it is already

 Comments?
 
 -- 
 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..fd6da71 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,46 @@ do_filesize (const char *path)
  
return buf.st_size;
  }
 +
 +int
 +do_copy_attributes (const char *src, const char *dest, int permissions, int 
 xattributes)
 +{
 +  int r;
 +  struct stat srcstat, deststat;
 +
 +  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 (permissions  ((srcstat.st_mode  0777) != (deststat.st_mode  
 0777))) {
 +CHROOT_IN;
 +r = chmod (dest, (srcstat.st_mode  0777));

I suspect you want 0 in order to copy sticky/setuid/setgid bits.
Perhaps those should be a separate flag, but we definitely want to
copy them!

 +CHROOT_OUT;
 +
 +if (r == -1) {
 +  reply_with_perror (chmod: %s, dest);
 +  return -1;
 +}
 +  }
 +
 +  if (xattributes  optgroup_linuxxattrs_available ()) {
 +if (!copy_xattrs (src, dest))
 +  return -1;
 +  }
 +
 +  return 0;
 +}
 diff --git a/daemon/xattr.c b/daemon/xattr.c
 index af8bfd4..97a94d5 100644
 --- a/daemon/xattr.c
 +++ b/daemon/xattr.c
 @@ -545,8 +545,98 @@ 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)
 +{
 +#if defined(HAVE_LISTXATTR)  defined(HAVE_GETXATTR)  
 defined(HAVE_SETXATTR)

I wonder if there are any platforms that lack one of listxattr,
getxattr and setxattr, but at the same time have one of these calls.
The xattr code (in general) is incredibly complex because of all these
tests.

I guess Mac OS X probably has none of them, and RHEL 5 / Ubuntu 10.10
probably had only some of them.  We don't care about RHEL 5 since it
now has its own branch (oldlinux), so the code might be made simpler
by an accompanying patch which reduces all of the HAVE_*XATTR* macros
down to a single one (HAVE_LINUX_XATTRS).

 +  ssize_t len, vlen, ret;
 +  CLEANUP_FREE char *buf = NULL, *attrval = NULL;
 +  size_t i, attrval_len = 0;
 +
 +  CHROOT_IN;
 +  len = listxattr (src, NULL, 0);
 +  CHROOT_OUT;
 +  if (len == -1) {
 +reply_with_perror (listxattr: %s, src);
 +goto error;
 +  }
 +
 +  buf = malloc (len);
 +  if (buf == NULL) {
 +reply_with_perror (malloc);
 +goto error;
 +  }
 +
 +  CHROOT_IN;
 +  len = listxattr (src, buf, len);
 +  CHROOT_OUT;
 +  if (len == -1) {
 +reply_with_perror (listxattr: %s, src);
 +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) {
 +

Re: [Libguestfs] RFC: copy-attributes command

2014-01-07 Thread Richard W.M. Jones
On Tue, Jan 07, 2014 at 09:04:36PM +, Richard W.M. Jones wrote:
 - Should it default to copying attributes?
 
 The common use case (for virt-edit) is: I want this other file which
 is identical to this original file, except in name and content.  That
 is (I think) an argument for copying everything by default.

Also there's no reason we can't have another bool optarg
to select whether the other bool optargs should default to
true or false ...

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine.  Supports Linux and Windows.
http://people.redhat.com/~rjones/virt-df/

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs