[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libguestfs] [PATCH 1/3] New API: case-sensitive-path to return case sensitive path on NTFS 3g fs



-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
New in Fedora 11: Fedora Windows cross-compiler. Compile Windows
programs, test, and build Windows installers. Over 70 libraries supprt'd
http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw
>From 36a0fc94e218706cb0ae10178d62c801fb875430 Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones redhat com>
Date: Mon, 26 Oct 2009 08:20:00 +0000
Subject: [PATCH 1/3] New API: case-sensitive-path to return case sensitive path on NTFS 3g fs

This function handles an annoyance/peculiarity of the Linux
NTFS 3g driver, which is that it exports NTFS filesystems with
names case sensitive, even though under Windows they would be
case insensitive.

This causes problems because the location of (eg.) c:\windows
might appear as /windows or /WINDOWS (etc) depending on the
inconsequential details of how it was originally created.

Example of this problem on a real Windows guest:

  ><fs> file /windows/system32/config/system.log
  libguestfs: error: file: access: /windows/system32/config/system.log: No such file or directory
  ><fs> case-sensitive-path /windows/system32/config/system.log
  /WINDOWS/system32/config/system.LOG
  ><fs> file /WINDOWS/system32/config/system.LOG
  MS Windows registry file, NT/2000 or above
---
 daemon/realpath.c |  112 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/MAX_PROC_NR   |    2 +-
 src/generator.ml  |   39 ++++++++++++++++++
 3 files changed, 152 insertions(+), 1 deletions(-)

diff --git a/daemon/realpath.c b/daemon/realpath.c
index 706af42..c638a21 100644
--- a/daemon/realpath.c
+++ b/daemon/realpath.c
@@ -23,6 +23,10 @@
 #include <string.h>
 #include <unistd.h>
 #include <limits.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "ignore-value.h"
 
 #include "daemon.h"
 #include "actions.h"
@@ -42,3 +46,111 @@ do_realpath (const char *path)
 
   return ret;			/* caller frees */
 }
+
+char *
+do_case_sensitive_path (const char *path)
+{
+  char ret[PATH_MAX+1] = "/";
+  size_t next = 1;
+
+  /* MUST chdir ("/") before leaving this function. */
+  if (chdir (sysroot) == -1) {
+    reply_with_perror ("%s", sysroot);
+    return NULL;
+  }
+
+  /* First character is a '/'.  Take each subsequent path element
+   * and follow it.
+   */
+  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");
+      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);
+      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;
+
+    /* 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")],
+   "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>
+
+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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]