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