Author: trasz
Date: Wed Sep  2 08:08:57 2009
New Revision: 196754
URL: http://svn.freebsd.org/changeset/base/196754

Log:
  Add NFSv4 ACL support to cp(1) and fix a few memory leaks.
  
  Note that this changes error reporting behaviour somewhat - before,
  no error was reported if ACL couldn't be copied because the target
  filesystem doesn't support ACLs.  Now, it will be reported - of course,
  only if there actually is an ACL to copy.
  
  Reviewed by:  rwatson

Modified:
  head/bin/cp/utils.c

Modified: head/bin/cp/utils.c
==============================================================================
--- head/bin/cp/utils.c Wed Sep  2 05:26:59 2009        (r196753)
+++ head/bin/cp/utils.c Wed Sep  2 08:08:57 2009        (r196754)
@@ -377,24 +377,52 @@ setfile(struct stat *fs, int fd)
 int
 preserve_fd_acls(int source_fd, int dest_fd)
 {
-       struct acl *aclp;
        acl_t acl;
+       acl_type_t acl_type;
+       int acl_supported = 0, ret, trivial;
 
-       if (fpathconf(source_fd, _PC_ACL_EXTENDED) != 1 ||
-           fpathconf(dest_fd, _PC_ACL_EXTENDED) != 1)
+       ret = fpathconf(source_fd, _PC_ACL_NFS4);
+       if (ret > 0 ) {
+               acl_supported = 1;
+               acl_type = ACL_TYPE_NFS4;
+       } else if (ret < 0 && errno != EINVAL) {
+               warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", to.p_path);
+               return (1);
+       }
+       if (acl_supported == 0) {
+               ret = fpathconf(source_fd, _PC_ACL_EXTENDED);
+               if (ret > 0 ) {
+                       acl_supported = 1;
+                       acl_type = ACL_TYPE_ACCESS;
+               } else if (ret < 0 && errno != EINVAL) {
+                       warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
+                           to.p_path);
+                       return (1);
+               }
+       }
+       if (acl_supported == 0)
                return (0);
-       acl = acl_get_fd(source_fd);
+
+       acl = acl_get_fd_np(source_fd, acl_type);
        if (acl == NULL) {
                warn("failed to get acl entries while setting %s", to.p_path);
                return (1);
        }
-       aclp = &acl->ats_acl;
-       if (aclp->acl_cnt == 3)
+       if (acl_is_trivial_np(acl, &trivial)) {
+               warn("acl_is_trivial() failed for %s", to.p_path);
+               acl_free(acl);
+               return (1);
+       }
+       if (trivial) {
+               acl_free(acl);
                return (0);
-       if (acl_set_fd(dest_fd, acl) < 0) {
+       }
+       if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) {
                warn("failed to set acl entries for %s", to.p_path);
+               acl_free(acl);
                return (1);
        }
+       acl_free(acl);
        return (0);
 }
 
@@ -405,10 +433,31 @@ preserve_dir_acls(struct stat *fs, char 
        int (*aclsetf)(const char *, acl_type_t, acl_t);
        struct acl *aclp;
        acl_t acl;
+       acl_type_t acl_type;
+       int acl_supported = 0, ret, trivial;
 
-       if (pathconf(source_dir, _PC_ACL_EXTENDED) != 1 ||
-           pathconf(dest_dir, _PC_ACL_EXTENDED) != 1)
+       ret = pathconf(source_dir, _PC_ACL_NFS4);
+       if (ret > 0) {
+               acl_supported = 1;
+               acl_type = ACL_TYPE_NFS4;
+       } else if (ret < 0 && errno != EINVAL) {
+               warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", source_dir);
+               return (1);
+       }
+       if (acl_supported == 0) {
+               ret = pathconf(source_dir, _PC_ACL_EXTENDED);
+               if (ret > 0) {
+                       acl_supported = 1;
+                       acl_type = ACL_TYPE_ACCESS;
+               } else if (ret < 0 && errno != EINVAL) {
+                       warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
+                           source_dir);
+                       return (1);
+               }
+       }
+       if (acl_supported == 0)
                return (0);
+
        /*
         * If the file is a link we will not follow it
         */
@@ -419,34 +468,48 @@ preserve_dir_acls(struct stat *fs, char 
                aclgetf = acl_get_file;
                aclsetf = acl_set_file;
        }
-       /*
-        * Even if there is no ACL_TYPE_DEFAULT entry here, a zero
-        * size ACL will be returned. So it is not safe to simply
-        * check the pointer to see if the default ACL is present.
-        */
-       acl = aclgetf(source_dir, ACL_TYPE_DEFAULT);
+       if (acl_type == ACL_TYPE_ACCESS) {
+               /*
+                * Even if there is no ACL_TYPE_DEFAULT entry here, a zero
+                * size ACL will be returned. So it is not safe to simply
+                * check the pointer to see if the default ACL is present.
+                */
+               acl = aclgetf(source_dir, ACL_TYPE_DEFAULT);
+               if (acl == NULL) {
+                       warn("failed to get default acl entries on %s",
+                           source_dir);
+                       return (1);
+               }
+               aclp = &acl->ats_acl;
+               if (aclp->acl_cnt != 0 && aclsetf(dest_dir,
+                   ACL_TYPE_DEFAULT, acl) < 0) {
+                       warn("failed to set default acl entries on %s",
+                           dest_dir);
+                       acl_free(acl);
+                       return (1);
+               }
+               acl_free(acl);
+       }
+       acl = aclgetf(source_dir, acl_type);
        if (acl == NULL) {
-               warn("failed to get default acl entries on %s",
-                   source_dir);
+               warn("failed to get acl entries on %s", source_dir);
                return (1);
        }
-       aclp = &acl->ats_acl;
-       if (aclp->acl_cnt != 0 && aclsetf(dest_dir,
-           ACL_TYPE_DEFAULT, acl) < 0) {
-               warn("failed to set default acl entries on %s",
-                   dest_dir);
+       if (acl_is_trivial_np(acl, &trivial)) {
+               warn("acl_is_trivial() failed on %s", source_dir);
+               acl_free(acl);
                return (1);
        }
-       acl = aclgetf(source_dir, ACL_TYPE_ACCESS);
-       if (acl == NULL) {
-               warn("failed to get acl entries on %s", source_dir);
-               return (1);
+       if (trivial) {
+               acl_free(acl);
+               return (0);
        }
-       aclp = &acl->ats_acl;
-       if (aclsetf(dest_dir, ACL_TYPE_ACCESS, acl) < 0) {
+       if (aclsetf(dest_dir, acl_type, acl) < 0) {
                warn("failed to set acl entries on %s", dest_dir);
+               acl_free(acl);
                return (1);
        }
+       acl_free(acl);
        return (0);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to