cp: Copy extended attributes with option -p
authorKrzysztof Sasiak <k.sasiak@samsung.com>
Thu, 6 Nov 2014 16:36:55 +0000 (17:36 +0100)
committerJosé Bollo <jose.bollo@open.eurogiciel.org>
Tue, 31 Mar 2015 12:32:25 +0000 (14:32 +0200)
Change-Id: I3517b5f40d1c2be570cbef4b60192abd043bd984

toys/posix/cp.c

index 0502c25..9518730 100644 (file)
@@ -90,6 +90,8 @@ config INSTALL
 #include <sys/smack.h>
 #endif //USE_SMACK
 
+#include <sys/xattr.h>
+
 GLOBALS(
   // install's options
   char *group;
@@ -253,6 +255,61 @@ int cp_node(struct dirtree *try)
           fdout = openat(cfd, catch, O_RDWR|O_CREAT|O_TRUNC, try->st.st_mode);
           if (fdout >= 0) {
             xsendfile(fdin, fdout);
+
+            // Duplicate xattrs for new file
+            if (flags & FLAG_p) {
+              ssize_t buffer_len = flistxattr(fdin, NULL, 0);
+
+              if (buffer_len > 0) {
+                char *xattrs_buffer = malloc(buffer_len);
+
+                // If we don't succeed, then we don't copy the xattrs
+                if (xattrs_buffer != NULL) {
+                  buffer_len = flistxattr(fdin, xattrs_buffer, buffer_len);
+                  char *tmp_buffer = xattrs_buffer;
+
+                  while (buffer_len > 0) {
+                    int len = strlen(tmp_buffer)+1;
+                    char *xattr_value = NULL;
+                    //Fetch size of xattr value
+                    ssize_t xattr_len = fgetxattr(fdin, tmp_buffer, xattr_value, 0);
+
+                    if (xattr_len == -1)
+                      goto exit_xattr;
+
+                    errno = 0;
+                    xattr_value = malloc(xattr_len);
+
+                    if (xattr_value == NULL)
+                      goto exit_xattr;
+
+                    xattr_len = fgetxattr(fdin, tmp_buffer, xattr_value, xattr_len);
+
+                    if (xattr_len == -1) {
+                      free(xattr_value);
+                      goto exit_xattr;
+                    }
+
+                    int ret = fsetxattr(fdout, tmp_buffer, xattr_value, xattr_len, 0);
+                    free(xattr_value);
+
+                    if (ret == -1) {
+                      //Something failed, we cannot fix it anyway, hence we break the loop
+                      fprintf(stderr, "cp: cannot apply extended attributes, \
+                        probably not supported by target filesystem");
+                      break;
+                    };
+
+                    tmp_buffer += len;
+                    buffer_len -= len;
+                  }
+
+exit_xattr:
+                free(xattrs_buffer);
+                errno = 0;
+                }
+              }
+            }
             err = 0;
           }
           close(fdin);