+int apply_default_acl(const char* path, 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);
+
+ basename_path_copy = strdup(path);
+ if (basename_path_copy == NULL) {
+ perror("apply_default_acl (strdup)");
+ result = ACL_ERROR;
+ goto cleanup;
+ }
+ char* child = basename(basename_path_copy);
+
+ /* Just kidding, if the path is "." or "..", then dirname will do
+ * the wrong thing and give us "." as its parent, too. So, we handle
+ * those as special cases. We use "child" instead of "path" here to
+ * catch things like "./" and "../"
+ */
+ bool path_is_dots = strcmp(child, ".") == 0 || strcmp(child, "..") == 0;
+ char dots_parent[6] = "../";
+ if (path_is_dots) {
+ parent = strcat(dots_parent, child);
+ }
+
+ 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().
+ *
+ * Note that if the basename is "." or "..", then we don't want to
+ * open it relative to the parent_fd, so we need another special
+ * case for those paths here.
+ */
+ if (path_is_dots) {
+ fd = open(child, O_NOFOLLOW);
+ }
+ else {
+ fd = openat(parent_fd, child, 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, 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;
+ }
+ if (fd > 0 && close(fd) == CLOSE_ERROR) {
+ perror("apply_default_acl (close fd)");
+ result = ACL_ERROR;
+ }
+ return result;