There's a bug (exposed by the most recent test case) in the way the
path "." is handled. Specifically, the dirname() function miscomputes
its parent path as ".", which is clearly not correct.
In this commit, a special case is added for the path ".", and the test
suite passes once more. The implementation is a bit of a hack, however,
and will be improved once the same issue with ".." has been dealt with.
return ACL_ERROR;
}
char* parent = dirname(dirname_path_copy);
return ACL_ERROR;
}
char* parent = dirname(dirname_path_copy);
- parent_fd = safe_open(parent, O_DIRECTORY | O_NOFOLLOW);
+
+ /* Just kidding, if the path is ".", then dirname will do the wrong
+ * thing and give us "." as its parent, too. So, we handle that as a
+ * special case.
+ *
+ * WARNING: it is important that "parent" itself is not used after
+ * this point; otherwise we would need to store the correct parent
+ * path in there. But since everything uses file descriptors from
+ * now on, we only need to ensure that we get the correct parent_fd
+ * below. */
+ if (strcmp(path, ".") == 0 && strcmp(parent, ".") == 0) {
+ parent_fd = safe_open("..", O_DIRECTORY | O_NOFOLLOW);
+ }
+ else {
+ 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)
if (parent_fd == OPEN_ERROR) {
if (errno == ELOOP || errno == ENOTDIR) {
/* We hit a symlink, either in the last path component (ELOOP)
result = ACL_ERROR;
goto cleanup;
}
result = ACL_ERROR;
goto cleanup;
}
- fd = openat(parent_fd, basename(basename_path_copy), O_NOFOLLOW);
+
+ /* If the basename is ".", then we don't want to open "." relative
+ to the parent_fd, so we need another special case for that
+ path. */
+ if (strcmp(path, ".") == 0 && strcmp(parent, ".") == 0) {
+ fd = open(".", O_NOFOLLOW);
+ }
+ else {
+ 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)
if (fd == OPEN_ERROR) {
if (errno == ELOOP || errno == ENOTDIR) {
/* We hit a symlink, either in the last path component (ELOOP)