Index: bin/setfacl/setfacl.c =================================================================== --- bin/setfacl/setfacl.c +++ bin/setfacl/setfacl.c @@ -73,6 +73,7 @@ static acl_type_t acl_type = ACL_TYPE_ACCESS; static int handle_file(FTS *ftsp, FTSENT *file); +static void clear_inheritance_flags(const FTSENT *file, acl_t acl); static char **stdin_files(void); static void usage(void); @@ -124,6 +125,39 @@ return (files_list); } +/* + * Remove any inheritance flags from NFSv4 ACLs when running in recursive + * mode. This is to avoid files being assigned identical ACLs to their + * parent directory while also being set to inherit them. + * + * The acl argument is assumed to be valid. + */ +static void +clear_inheritance_flags(const FTSENT *file, acl_t acl) +{ + acl_entry_t acl_entry; + acl_flagset_t acl_flagset; + int acl_brand, entry_id; + + (void)acl_get_brand_np(acl, &acl_brand); + if (!R_flag || acl_brand != ACL_BRAND_NFS4 || file->fts_info == FTS_D) + return; + + entry_id = ACL_FIRST_ENTRY; + while (acl_get_entry(acl, entry_id, &acl_entry) == 1) { + entry_id = ACL_NEXT_ENTRY; + (void)acl_get_flagset_np(acl_entry, &acl_flagset); + if (acl_get_flag_np(acl_flagset, ACL_ENTRY_INHERIT_ONLY)) { + (void)acl_delete_entry(acl, acl_entry); + continue; + } + (void)acl_delete_flag_np(acl_flagset, + ACL_ENTRY_FILE_INHERIT | + ACL_ENTRY_DIRECTORY_INHERIT | + ACL_ENTRY_NO_PROPAGATE_INHERIT); + } +} + static int handle_file(FTS *ftsp, FTSENT *file) { @@ -198,10 +232,14 @@ switch(entry->op) { case OP_ADD_ACL: + if (R_flag && acl_type == ACL_TYPE_NFS4) + clear_inheritance_flags(file, entry->acl); local_error += add_acl(entry->acl, entry->entry_number, &acl, file->fts_path); break; case OP_MERGE_ACL: + if (R_flag && acl_type == ACL_TYPE_NFS4) + clear_inheritance_flags(file, entry->acl); local_error += merge_acl(entry->acl, &acl, file->fts_path); need_mask = true;