From 973581780d8a006f336684fef6762801402d775d Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 17 Jul 2012 13:44:45 +0100 Subject: [PATCH] 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. --- daemon/realpath.c | 34 ++++++++++++++++++++-------------- generator/generator_actions.ml | 5 ++++- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/daemon/realpath.c b/daemon/realpath.c index edf6da0a0..aae22aeed 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; - } + /* Some errors are OK provided we've reached the end of the path. */ + if (is_end && (errno == ENOTDIR || errno == ENOENT)) + break; - if (*path) { - reply_with_error ("%s: non-directory element in path", name); - goto error; - } + 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); diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 932212691..90cc661f0 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -5909,7 +5909,10 @@ The result list is not sorted. [["mkdir"; "/case_sensitive_path3"]; ["mkdir"; "/case_sensitive_path3/bbb"]; ["touch"; "/case_sensitive_path3/bbb/c"]; - ["case_sensitive_path"; "/case_SENSITIVE_path3/bbb/../bbb/C"]]) + ["case_sensitive_path"; "/case_SENSITIVE_path3/bbb/../bbb/C"]]); + InitScratchFS, Always, TestOutput ( + [["mkdir"; "/case_sensitive_path4"]; + ["case_sensitive_path"; "/case_SENSITIVE_path4/new_file"]], "/case_sensitive_path4/new_file") ]; shortdesc = "return true path on case-insensitive filesystem"; longdesc = "\