summaryrefslogtreecommitdiffstats
path: root/daemon/realpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/realpath.c')
-rw-r--r--daemon/realpath.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/daemon/realpath.c b/daemon/realpath.c
index edf6da0a..aae22aee 100644
--- a/daemon/realpath.c
+++ b/daemon/realpath.c
@@ -78,7 +78,7 @@ do_realpath (const char *path)
#endif /* !HAVE_REALPATH */
-static int find_path_element (int fd_cwd, char *name, size_t *name_len_ret);
+static int find_path_element (int fd_cwd, int is_end, char *name, size_t *name_len_ret);
char *
do_case_sensitive_path (const char *path)
@@ -86,7 +86,7 @@ do_case_sensitive_path (const char *path)
char ret[PATH_MAX+1] = "/";
char name[NAME_MAX+1];
size_t next = 1;
- int fd_cwd, fd2, err;
+ int fd_cwd, fd2, err, is_end;
size_t i;
char *retp;
@@ -124,12 +124,13 @@ do_case_sensitive_path (const char *path)
/* Skip to next element in path (for the next loop iteration). */
path += i;
+ is_end = *path == 0;
/* Read the current directory looking (case insensitively) for
* this element of the path. This replaces 'name' with the
* correct case version.
*/
- if (find_path_element (fd_cwd, name, &i) == -1)
+ if (find_path_element (fd_cwd, is_end, name, &i) == -1)
goto error;
/* Add the real name of this path element to the return value. */
@@ -151,16 +152,12 @@ do_case_sensitive_path (const char *path)
fd_cwd = fd2;
errno = err;
if (fd_cwd == -1) {
- /* ENOTDIR is OK provided we've reached the end of the path. */
- if (errno != ENOTDIR) {
- reply_with_perror ("openat: %s", name);
- goto error;
- }
-
- if (*path) {
- reply_with_error ("%s: non-directory element in path", name);
- goto error;
- }
+ /* Some errors are OK provided we've reached the end of the path. */
+ if (is_end && (errno == ENOTDIR || errno == ENOENT))
+ break;
+
+ reply_with_perror ("openat: %s", name);
+ goto error;
}
}
@@ -184,7 +181,8 @@ do_case_sensitive_path (const char *path)
/* 'fd_cwd' is a file descriptor pointing to an open directory.
* 'name' is a buffer of NAME_MAX+1 characters in size which initially
- * contains the path element to search for.
+ * contains the path element to search for. 'is_end' is a flag
+ * indicating if this is the last path element.
*
* We search the directory looking for a path element that case
* insensitively matches 'name' and update the 'name' buffer.
@@ -193,7 +191,7 @@ do_case_sensitive_path (const char *path)
* and return -1.
*/
static int
-find_path_element (int fd_cwd, char *name, size_t *name_len_ret)
+find_path_element (int fd_cwd, int is_end, char *name, size_t *name_len_ret)
{
int fd2;
DIR *dir;
@@ -226,6 +224,14 @@ find_path_element (int fd_cwd, char *name, size_t *name_len_ret)
return -1;
}
+ if (d == NULL && is_end) {
+ /* Last path element: return it as-is, assuming that the user will
+ * create a new file or directory (RHBZ#840115).
+ */
+ closedir (dir);
+ return 0;
+ }
+
if (d == NULL) {
reply_with_error ("%s: no file or directory found with this name", name);
closedir (dir);