+ acl_free(new_acl);
+ acl_free(new_acl_unmasked);
+ return result;
+}
+
+
+/**
+ * @brief Apply parent default ACL to a path and optionally its children.
+ *
+ * This overwrites any existing ACLs on the target, and, if @c
+ * recursive is @c true, its children. When @c recursive is @c true,
+ * the "worst" result encountered is returned as the overall result.
+ *
+ * @param path
+ * The path whose ACL we would like to reset to its default.
+ *
+ * @param no_exec_mask
+ * The value (either true or false) of the --no-exec-mask flag.
+ *
+ * @param recursive
+ * Should we recurse into subdirectories?
+ *
+ * @return
+ * - @c ACL_SUCCESS - The parent default ACLs were inherited successfully.
+ * - @c ACL_FAILURE - If symlinks or hard links are encountered.
+ * - @c ACL_ERROR - Unexpected library error.
+ */
+int apply_default_acl(const char* path, bool no_exec_mask, bool recursive) {
+
+ if (path == NULL) {
+ errno = EINVAL;
+ perror("apply_default_acl (args)");
+ return ACL_ERROR;
+ }
+
+ /* Define these next three variables here because we may have to
+ * jump to the cleanup routine which expects them to exist.
+ */
+
+ /* Our return value. */
+ int result = ACL_SUCCESS;
+
+ /* The file descriptor corresponding to "path" */
+ int fd = 0;
+
+ /* The file descriptor for the directory containing "path" */
+ int parent_fd = 0;
+
+ /* dirname() and basename() mangle their arguments, so we need
+ to make copies of "path" before using them. */
+ char* dirname_path_copy = NULL;
+ char* basename_path_copy = NULL;
+
+ /* Get the parent directory of "path" with dirname(), which happens
+ * to murder its argument and necessitates a path_copy. */
+ dirname_path_copy = strdup(path);
+ if (dirname_path_copy == NULL) {
+ perror("apply_default_acl (strdup)");
+ return ACL_ERROR;
+ }
+ char* parent = dirname(dirname_path_copy);
+ parent_fd = safe_open(parent, O_DIRECTORY | O_NOFOLLOW);
+ if (parent_fd == OPEN_ERROR) {
+ if (errno == ELOOP || errno == ENOTDIR) {
+ /* We hit a symlink, either in the last path component (ELOOP)
+ or higher up (ENOTDIR). */
+ result = ACL_FAILURE;
+ goto cleanup;
+ }
+ else {
+ perror("apply_default_acl (open parent fd)");
+ result = ACL_ERROR;
+ goto cleanup;
+ }
+ }
+
+ /* We already obtained the parent fd safely, so if we use the
+ basename of path here instead of the full thing, then we can get
+ away with using openat() and spare ourselves the slowness of
+ another safe_open(). */
+ basename_path_copy = strdup(path);
+ if (basename_path_copy == NULL) {
+ perror("apply_default_acl (strdup)");
+ return ACL_ERROR;
+ }
+ fd = openat(parent_fd, basename(basename_path_copy), O_NOFOLLOW);
+ if (fd == OPEN_ERROR) {
+ if (errno == ELOOP || errno == ENOTDIR) {
+ /* We hit a symlink, either in the last path component (ELOOP)
+ or higher up (ENOTDIR). */
+ result = ACL_FAILURE;
+ goto cleanup;
+ }
+ else {
+ perror("apply_default_acl (open fd)");
+ result = ACL_ERROR;
+ goto cleanup;
+ }
+ }
+
+ result = apply_default_acl_fds(parent_fd, fd, no_exec_mask, recursive);
+
+ cleanup:
+ free(dirname_path_copy);
+ free(basename_path_copy);
+
+ if (parent_fd > 0 && close(parent_fd) == CLOSE_ERROR) {
+ perror("apply_default_acl (close parent_fd)");
+ result = ACL_ERROR;