summaryrefslogtreecommitdiffstats
path: root/daemon/realpath.c
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-07-17 13:44:45 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-07-17 14:37:03 +0100
commit973581780d8a006f336684fef6762801402d775d (patch)
tree599e624442039a6a00ca4edf8f3a52a5aea69238 /daemon/realpath.c
parentac0373bdecfabe6acf99d3662e5117de73fa2aef (diff)
downloadlibguestfs-973581780d8a006f336684fef6762801402d775d.tar.gz
libguestfs-973581780d8a006f336684fef6762801402d775d.tar.xz
libguestfs-973581780d8a006f336684fef6762801402d775d.zip
case_sensitive_path: Allow trailing path element to be missing (RHBZ#840115).
case_sensitive_path is undefined when the final path element doesn't exist. Currently it returns an error, but this means that creating a new file doesn't work as expected: $ guestfish --rw -i -d windows touch 'win:c:\blah' libguestfs: error: case_sensitive_path: blah no file or directory found with this name We should allow this case (provided there is no trailing slash) so that new files or directories can be created.
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);