return OPEN_ERROR;
}
- int fd = 0;
- if (strcmp(abspath, "/") == 0) {
- fd = open("/", flags | O_DIRECTORY);
- }
- else {
+ bool abspath_is_root = (strcmp(abspath, "/") == 0);
+ int rootflags = flags | O_DIRECTORY;
+ if (!abspath_is_root) {
/* Use O_PATH for some added safety if "/" is not our target */
- fd = open("/", flags | O_DIRECTORY | O_PATH);
+ rootflags |= O_PATH;
}
- if (fd == OPEN_ERROR) {
+ int rootfd = open("/", rootflags);
+ if (rootfd == OPEN_ERROR) {
perror("safe_open (open)");
return OPEN_ERROR;
}
- if (strcmp(abspath, "/") == 0) {
- return fd;
+ if (abspath_is_root) {
+ return rootfd;
}
- int result = safe_open_ex(fd, abspath+1, flags);
- if (close(fd) == CLOSE_ERROR) {
+ int result = safe_open_ex(rootfd, abspath+1, flags);
+ if (close(rootfd) == CLOSE_ERROR) {
perror("safe_open (close)");
return OPEN_ERROR;
}
return ACL_ERROR;
}
- size_t src_size_guess = fgetxattr(src_fd, src_name, NULL, 0);
+ ssize_t src_size_guess = fgetxattr(src_fd, src_name, NULL, 0);
if (src_size_guess == XATTR_ERROR) {
if (errno == ENODATA) {
/* A missing ACL isn't really an error. ENOATTR and ENODATA are
}
char* src_acl_p = alloca(src_size_guess);
/* The actual size may be smaller than our guess? I don't know. */
- size_t src_size = fgetxattr(src_fd, src_name, src_acl_p, (int)src_size_guess);
+ ssize_t src_size = fgetxattr(src_fd, src_name, src_acl_p, src_size_guess);
if (src_size == XATTR_ERROR) {
if (errno == ENODATA) {
/* A missing ACL isn't an error. */
/* 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. */
- char* path_copy = strdup(path);
- if (path_copy == NULL) {
+ dirname_path_copy = strdup(path);
+ if (dirname_path_copy == NULL) {
perror("apply_default_acl_ex (strdup)");
return ACL_ERROR;
}
- char* parent = dirname(path_copy);
+ 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) {
goto cleanup;
}
- fd = safe_open(path, O_NOFOLLOW);
+ /* 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_ex (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)
}
/* There's a good reason why we saved the ACL above, even though
- * we're about tto read it back into memory and mess with it on the
+ * we're about to read it back into memory and mess with it on the
* next line. The acl_copy_xattr() function is already a hack to let
* us copy default ACLs without resorting to path names; we simply
* have no way to read the parent's default ACL into memory using
*/
/* Now we potentially need to mask the execute permissions in the
- ACL on fd; or maybe now. */
+ ACL on fd; or maybe not. */
if (allow_exec) {
goto cleanup;
}
}
cleanup:
- free(path_copy);
+ free(dirname_path_copy);
+ free(basename_path_copy);
if (new_acl != (acl_t)NULL) {
acl_free(new_acl);
}