[Libguestfs] [PATCH 1/3] New API: case-sensitive-path to return case sensitive path on NTFS 3g fs
Matthew Booth
mbooth at redhat.com
Mon Oct 26 11:03:04 UTC 2009
On 26/10/09 09:20, Richard W.M. Jones wrote:
> +char *
> +do_case_sensitive_path (const char *path)
> +{
> + char ret[PATH_MAX+1] = "/";
Is PATH_MAX on Windows <= POSIX PATH_MAX? Does ntfs_3g honour this?
Seems like a grey area. It would be safer to realloc this buffer as
necessary. You also wouldn't need the strdup() at the end.
> + size_t next = 1;
> +
> + /* MUST chdir ("/") before leaving this function. */
> + if (chdir (sysroot) == -1) {
> + reply_with_perror ("%s", sysroot);
> + return NULL;
> + }
I'm not convinced chdir is necessary in this function if you use
openat() throughout.
> + /* First character is a '/'. Take each subsequent path element
> + * and follow it.
> + */
A check that *path == '/' wouldn't go amiss here. I'd stick an assert
in, but then DV might shoot me ;)
> + path++;
> + while (*path) {
> + size_t i = strcspn (path, "/");
> + if (i == 0) { /* "//" in path */
> + path++;
> + continue;
> + }
> + if ((i == 1&& path[0] == '.') ||
> + (i == 2&& path[0] == '.'&& path[1] == '.')) {
> + reply_with_error ("case_sensitive_path: path contained . or .. elements");
This string isn't internationalised. I won't mention all of these.
> + goto error;
> + }
> + if (i> NAME_MAX) {
> + reply_with_error ("case_sensitive_path: path element too long");
> + goto error;
> + }
> +
> + char name[NAME_MAX+1];
> + memcpy (name, path, i);
> + name[i] = '\0';
> +
> + /* Skip to next element in path (for the next loop iteration). */
> + path += i;
> + if (*path == '/') path++;
> +
> + /* Read the current directory looking (case insensitively) for
> + * this element of the path.
> + */
> + DIR *dir = opendir (".");
> + if (dir == NULL) {
> + reply_with_perror ("opendir");
> + goto error;
> + }
> +
> + struct dirent *d = NULL;
> +
> + while ((d = readdir (dir)) != NULL) {
> + if (strcasecmp (d->d_name, name) == 0)
> + break;
> + }
> +
> + if (closedir (dir) == -1) {
> + reply_with_perror ("closedir");
> + goto error;
> + }
> +
> + if (d == NULL) {
> + reply_with_error ("%s: no file or directory found with this name", name);
Non-internationalised string. This message is definitely for the user.
> + goto error;
> + }
> +
> + /* Add the real name of this path element to the return value. */
> + if (next> 1)
> + ret[next++] = '/';
> +
> + i = strlen (d->d_name);
> + if (next + i>= PATH_MAX) {
> + reply_with_error ("final path too long");
> + goto error;
> + }
> +
> + strcpy (&ret[next], d->d_name);
> + next += i;
> +
> + /* Is it a directory? Try going into it. */
> + if (chdir (d->d_name) == 0)
> + continue;
openat() and fstat() would be much nicer here.
> +
> + /* This is OK provided we've reached the end of the path. */
> + if (errno == ENOTDIR) {
> + if (*path) {
> + reply_with_error ("non-directory element in path");
> + goto error;
> + }
> + break;
> + }
> + }
> +
> + ignore_value (chdir ("/"));
> +
> + ret[next] = '\0';
> + char *retp = strdup (ret);
> + if (retp == NULL) {
> + reply_with_perror ("strdup");
> + return NULL;
> + }
> + return retp; /* caller frees */
> +
> + error:
> + ignore_value (chdir ("/"));
> + return NULL;
> +}
> diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
> index 0f11735..5381652 100644
> --- a/src/MAX_PROC_NR
> +++ b/src/MAX_PROC_NR
> @@ -1 +1 @@
> -196
> +197
> diff --git a/src/generator.ml b/src/generator.ml
> index cea5178..668002e 100755
> --- a/src/generator.ml
> +++ b/src/generator.ml
> @@ -3645,6 +3645,45 @@ The result list is not sorted.
>
> =back");
>
> + ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
> + [InitISOFS, Always, TestOutput (
> + [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
> + InitISOFS, Always, TestOutput (
> + [["case_sensitive_path"; "/Known-1"]], "/known-1");
> + InitBasicFS, Always, TestOutput (
> + [["mkdir"; "/a"];
> + ["mkdir"; "/a/bbb"];
> + ["touch"; "/a/bbb/c"];
> + ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c")],
These don't exercise the following cases you've coded for:
/
/foo//bar
/foo/../bar
/foo///bar/
> + "return true path on case-insensitive filesystem",
> + "\
> +This command handles a peculiarity of the Linux ntfs-3g
> +filesystem driver (and probably others), which is that although
> +the underlying filesystem is case-insensitive, the driver
> +exports the filesystem to Linux as case-sensitive.
> +
> +One consequence of this is that special directories such
> +as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
> +(or other things) depending on the precise details of how
> +they were created. In Windows itself this would not be
> +a problem.
> +
> +Bug or feature? You decide:
> +L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
It's definitely a bug ;)
> +
> +This function resolves the true case of each element in the
> +path and returns the case-sensitive path.
> +
> +Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
> +might return C<\"/WINDOWS/system32\"> (the exact return value
> +would depend on details of how the directories were originally
> +created under Windows).
> +
> +I<Note>:
> +This function does not handle drive names, backslashes etc.
> +
> +See also C<guestfs_realpath>.");
> +
> ]
>
> let all_functions = non_daemon_functions @ daemon_functions
> -- 1.6.5.rc2
This API seems like an unfortunate pimple. Would it not be better to
*not* export this API, and instead call this automatically everywhere
the daemon opens a file on ntfs?
Matt
--
Matthew Booth, RHCA, RHCSS
Red Hat Engineering, Virtualisation Team
M: +44 (0)7977 267231
GPG ID: D33C3490
GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
More information about the Libguestfs
mailing list