+
+int any_can_execute(const char* path) {
+ /* Returns 1 if any ACL entry has execute access, 0 if none do, and
+ -1 on error. */
+ acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS);
+
+ if (acl == (acl_t)NULL) {
+ return 0;
+ }
+
+ /* Our return value. */
+ int result = 0;
+
+ if (acl_is_minimal(&acl)) {
+ mode_t mode = get_mode(path);
+ if (mode & (S_IXUSR | S_IXOTH | S_IXGRP)) {
+ result = 1;
+ goto cleanup;
+ }
+ else {
+ result = 0;
+ goto cleanup;
+ }
+ }
+
+ acl_entry_t entry;
+ int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+
+ while (ge_result == 1) {
+ acl_permset_t permset;
+
+ int ps_result = acl_get_permset(entry, &permset);
+ if (ps_result == -1) {
+ perror("any_can_execute (acl_get_permset)");
+ result = -1;
+ goto cleanup;
+ }
+
+ int gp_result = acl_get_perm(permset, ACL_EXECUTE);
+ if (gp_result == -1) {
+ perror("any_can_execute (acl_get_perm)");
+ result = -1;
+ goto cleanup;
+ }
+
+ if (gp_result == 1) {
+ result = 1;
+ goto cleanup;
+ }
+
+ ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
+ }
+
+ if (ge_result == -1) {
+ perror("any_can_execute (acl_get_entry)");
+ result = -1;
+ goto cleanup;
+ }
+
+ cleanup:
+ acl_free(acl);
+ return result;
+}
+
+
+int inherit_default_acl(const char* path, const char* parent) {
+ /* Inherit the default ACL from parent to path. This overwrites any
+ existing default ACL. Returns 1 for success, 0 for failure, and
+ -1 on error. */
+
+ /* Our return value. */
+ int result = 1;
+
+ if (path == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (!is_directory(path) || !is_directory(parent)) {
+ return 0;
+ }
+
+ acl_t parent_acl = acl_get_file(parent, ACL_TYPE_DEFAULT);
+ if (parent_acl == (acl_t)NULL) {
+ return 0;
+ }
+
+ acl_t path_acl = acl_dup(parent_acl);
+
+ if (path_acl == (acl_t)NULL) {
+ perror("inherit_default_acl (acl_dup)");
+ acl_free(parent_acl);
+ return -1;
+ }
+
+ int sf_result = acl_set_file(path, ACL_TYPE_DEFAULT, path_acl);
+ if (sf_result == -1) {
+ perror("inherit_default_acl (acl_set_file)");
+ result = -1;
+ goto cleanup;
+ }
+
+ cleanup:
+ acl_free(path_acl);
+ return result;
+}
+
+
+int wipe_acls(const char* path) {
+ /* Remove ACL_USER, ACL_GROUP, and ACL_MASK entries from
+ path. Returns 1 for success, 0 for failure, and -1 on error. */
+
+ if (path == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* Finally, remove individual named/mask entries. */
+ acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS);
+ if (acl == (acl_t)NULL) {
+ perror("wipe_acls (acl_get_file)");
+ return -1;
+ }
+
+ /* Our return value. */
+ int result = 1;
+
+ acl_entry_t entry;
+ int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+
+ while (ge_result == 1) {
+ int d_result = acl_delete_entry(acl, entry);
+ if (d_result == -1) {
+ perror("wipe_acls (acl_delete_entry)");
+ result = -1;
+ goto cleanup;
+ }
+
+ ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
+ }
+
+ /* Catches the first acl_get_entry as well as the ones at the end of
+ the loop. */
+ if (ge_result == -1) {
+ perror("wipe_acls (acl_get_entry)");
+ result = -1;
+ goto cleanup;
+ }
+
+ int sf_result = acl_set_file(path, ACL_TYPE_ACCESS, acl);
+ if (sf_result == -1) {
+ perror("wipe_acls (acl_set_file)");
+ result = -1;
+ goto cleanup;
+ }
+
+ cleanup:
+ acl_free(acl);
+ return result;