--- /usr/src/bin/setfacl/setfacl.c 2011-02-03 12:11:02.303496318 -0700 +++ /tank/jails/dev/usr/src/bin/setfacl/setfacl.c 2011-02-08 10:47:18.190936489 -0700 @@ -23,7 +23,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - +#define _ACL_PRIVATE #include __FBSDID("$FreeBSD$"); @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,8 @@ static void add_filename(const char *filename); static void usage(void); +static void recurse_directory(const char *dirname, int r_flag); +static acl_t remove_invalid_inherit(struct stat *sb, acl_t acl); static void add_filename(const char *filename) @@ -63,19 +66,83 @@ usage(void) { - fprintf(stderr, "usage: setfacl [-bdhkn] [-a position entries] " + fprintf(stderr, "usage: setfacl [-bdhknR] [-a position entries] " "[-m entries] [-M file] [-x entries] [-X file] [file ...]\n"); exit(1); } +static void +recurse_directory(const char *dirname, int r_flag) +{ + DIR *dirp; + struct dirent *ent; + struct stat sb; + char newpath[PATH_MAX+1]; + + if (stat(dirname, &sb) == -1) { + warn("%s: stat() failed", dirname); + return; + } + + add_filename(dirname); + + if (r_flag == 0 || S_ISDIR(sb.st_mode) == 0) + return; + + dirp = opendir(dirname); + while ((ent = readdir(dirp)) != NULL) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) + continue; + + snprintf(newpath, PATH_MAX, "%s/%s", dirname, ent->d_name); + + if (stat(newpath, &sb) == -1) { + warn("%s: stat() failed", newpath); + continue; + } + + if (S_ISDIR(sb.st_mode)) + recurse_directory(newpath, r_flag); + + add_filename(strdup(newpath)); + } + closedir(dirp); +} + +static acl_t +remove_invalid_inherit(struct stat *sb, acl_t acl) +{ + acl_t acl_new; + int acl_brand; + acl_entry_t entry; + int entry_id; + + acl_get_brand_np(acl, &acl_brand); + if (acl_brand != ACL_BRAND_NFS4) + return acl; + + if (S_ISDIR(sb->st_mode) != 0) + return acl; + + acl_new = acl_dup(acl); + + entry_id = ACL_FIRST_ENTRY; + while (acl_get_entry(acl_new, entry_id, &entry) == 1) { + entry_id = ACL_NEXT_ENTRY; + entry->ae_flags = 0; + } + + return acl_new; +} + int main(int argc, char *argv[]) { - acl_t acl; + acl_t acl, acl_backup; acl_type_t acl_type; char filename[PATH_MAX]; int local_error, carried_error, ch, i, entry_number, ret; - int h_flag; + int h_flag, r_flag; struct sf_file *file; struct sf_entry *entry; const char *fn_dup; @@ -84,12 +151,12 @@ acl_type = ACL_TYPE_ACCESS; carried_error = local_error = 0; - h_flag = have_mask = have_stdin = n_flag = need_mask = 0; + h_flag = have_mask = have_stdin = n_flag = need_mask = r_flag = 0; TAILQ_INIT(&entrylist); TAILQ_INIT(&filelist); - while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1) + while ((ch = getopt(argc, argv, "RM:X:a:bdhkm:nx:")) != -1) switch(ch) { case 'M': entry = zmalloc(sizeof(struct sf_entry)); @@ -167,6 +234,9 @@ } TAILQ_INSERT_TAIL(&entrylist, entry, next); break; + case 'R': + r_flag = 1; + break; default: usage(); break; @@ -193,7 +263,7 @@ } } else for (i = 0; i < argc; i++) - add_filename(argv[i]); + recurse_directory(argv[i], r_flag); /* cycle through each file */ TAILQ_FOREACH(file, &filelist, next) { @@ -250,12 +320,24 @@ switch(entry->op) { case OP_ADD_ACL: + acl_backup = entry->acl; + entry->acl = remove_invalid_inherit(&sb, entry->acl); local_error += add_acl(entry->acl, entry->entry_number, &acl, file->filename); + if (entry->acl != acl_backup) { + acl_free(entry->acl); + entry->acl = acl_backup; + } break; case OP_MERGE_ACL: + acl_backup = entry->acl; + entry->acl = remove_invalid_inherit(&sb, entry->acl); local_error += merge_acl(entry->acl, &acl, file->filename); + if (entry->acl != acl_backup) { + acl_free(entry->acl); + entry->acl = acl_backup; + } need_mask = 1; break; case OP_REMOVE_EXT: