mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
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.
(cherry picked from commit 973581780d)
This commit is contained in:
@@ -76,7 +76,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)
|
||||
@@ -84,7 +84,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;
|
||||
|
||||
@@ -122,12 +122,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. */
|
||||
@@ -149,16 +150,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +179,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.
|
||||
@@ -191,7 +189,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;
|
||||
@@ -224,6 +222,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);
|
||||
|
||||
@@ -4775,7 +4775,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")],
|
||||
"return true path on case-insensitive filesystem",
|
||||
"\
|
||||
This can be used to resolve case insensitive paths on
|
||||
|
||||
Reference in New Issue
Block a user