X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Futils%2Fmono-io-portability.c;h=979bb6037fd21ba9be040c408eca9cba4a265fe2;hb=6d1b90ae1befc5bd499c133822217c8a54c4253f;hp=e8e6c3fd0b92e204f99381789b56d590932d198e;hpb=2b6f9a70e5fe6263763878e6fd524900750f7c7c;p=mono.git diff --git a/mono/utils/mono-io-portability.c b/mono/utils/mono-io-portability.c index e8e6c3fd0b9..979bb6037fd 100644 --- a/mono/utils/mono-io-portability.c +++ b/mono/utils/mono-io-portability.c @@ -1,10 +1,27 @@ #include "config.h" -#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include #include +#include +#include +#include +#include +#include +#include +#include + +#ifndef DISABLE_PORTABILITY + +#include int __mono_io_portability_helpers = PORTABILITY_UNKNOWN; +static inline gchar *mono_portability_find_file_internal (GString **report, const gchar *pathname, gboolean last_exists); + void mono_portability_helpers_init (void) { const gchar *env; @@ -13,7 +30,7 @@ void mono_portability_helpers_init (void) return; __mono_io_portability_helpers = PORTABILITY_NONE; - + env = g_getenv ("MONO_IOMAP"); if (env != NULL) { /* parse the environment setting and set up some vars @@ -37,9 +54,347 @@ void mono_portability_helpers_init (void) } else if (!strncasecmp (options[i], "case", 4)) { __mono_io_portability_helpers |= PORTABILITY_CASE; } else if (!strncasecmp (options[i], "all", 3)) { - __mono_io_portability_helpers |= (PORTABILITY_DRIVE | - PORTABILITY_CASE); - } + __mono_io_portability_helpers |= (PORTABILITY_DRIVE | PORTABILITY_CASE); + } } - } + } +} + +/* Returns newly allocated string, or NULL on failure */ +static gchar *find_in_dir (DIR *current, const gchar *name) +{ + struct dirent *entry; + +#ifdef DEBUG + g_message ("%s: looking for [%s]\n", __func__, name); +#endif + + while((entry = readdir (current)) != NULL) { +#ifdef DEBUGX + g_message ("%s: found [%s]\n", __func__, entry->d_name); +#endif + + if (!g_ascii_strcasecmp (name, entry->d_name)) { + char *ret; + +#ifdef DEBUG + g_message ("%s: matched [%s] to [%s]\n", __func__, + entry->d_name, name); +#endif + + ret = g_strdup (entry->d_name); + closedir (current); + return ret; + } + } + +#ifdef DEBUG + g_message ("%s: returning NULL\n", __func__); +#endif + + closedir (current); + + return(NULL); +} + +static inline void append_report (GString **report, const gchar *format, ...) +{ +#if defined (_EGLIB_MAJOR) || GLIB_CHECK_VERSION(2,14,0) + va_list ap; + if (!*report) + *report = g_string_new (""); + + va_start (ap, format); + g_string_append_vprintf (*report, format, ap); + va_end (ap); +#else + g_assert_not_reached (); +#endif +} + +static inline void do_mono_profiler_iomap (GString **report, const char *pathname, const char *new_pathname) +{ + char *rep = NULL; + GString *tmp = report ? *report : NULL; + + if (tmp) { + if (tmp->len > 0) + rep = g_string_free (tmp, FALSE); + else + g_string_free (tmp, TRUE); + *report = NULL; + } + + mono_profiler_iomap (rep, pathname, new_pathname); + g_free (rep); +} + +gchar *mono_portability_find_file (const gchar *pathname, gboolean last_exists) +{ + GString *report = NULL; + gchar *ret; + + if (!pathname || !pathname [0]) + return NULL; + ret = mono_portability_find_file_internal (&report, pathname, last_exists); + + if (report) + g_string_free (report, TRUE); + + return ret; +} + +/* Returns newly-allocated string or NULL on failure */ +static inline gchar *mono_portability_find_file_internal (GString **report, const gchar *pathname, gboolean last_exists) +{ + gchar *new_pathname, **components, **new_components; + int num_components = 0, component = 0; + DIR *scanning = NULL; + size_t len; + gboolean drive_stripped = FALSE; + gboolean do_report = (mono_profiler_get_events () & MONO_PROFILE_IOMAP_EVENTS) != 0; + + if (IS_PORTABILITY_NONE) { + return(NULL); + } + + if (do_report) + append_report (report, " - Requested file path: '%s'\n", pathname); + + new_pathname = g_strdup (pathname); + +#ifdef DEBUG + g_message ("%s: Finding [%s] last_exists: %s\n", __func__, pathname, + last_exists?"TRUE":"FALSE"); +#endif + + if (last_exists && + access (new_pathname, F_OK) == 0) { +#ifdef DEBUG + g_message ("%s: Found it without doing anything\n", __func__); +#endif + return(new_pathname); + } + + /* First turn '\' into '/' and strip any drive letters */ + g_strdelimit (new_pathname, "\\", '/'); + +#ifdef DEBUG + g_message ("%s: Fixed slashes, now have [%s]\n", __func__, + new_pathname); +#endif + + if (IS_PORTABILITY_DRIVE && + g_ascii_isalpha (new_pathname[0]) && + (new_pathname[1] == ':')) { + int len = strlen (new_pathname); + + g_memmove (new_pathname, new_pathname+2, len - 2); + new_pathname[len - 2] = '\0'; + + if (do_report) { + append_report (report, " - Stripped drive letter.\n"); + drive_stripped = TRUE; + } +#ifdef DEBUG + g_message ("%s: Stripped drive letter, now looking for [%s]\n", + __func__, new_pathname); +#endif + } + + len = strlen (new_pathname); + if (len > 1 && new_pathname [len - 1] == '/') { + new_pathname [len - 1] = 0; +#ifdef DEBUG + g_message ("%s: requested name had a trailing /, rewritten to '%s'\n", + __func__, new_pathname); +#endif + } + + if (last_exists && + access (new_pathname, F_OK) == 0) { +#ifdef DEBUG + g_message ("%s: Found it\n", __func__); +#endif + if (do_report && drive_stripped) + do_mono_profiler_iomap (report, pathname, new_pathname); + + return(new_pathname); + } + + /* OK, have to work harder. Take each path component in turn + * and do a case-insensitive directory scan for it + */ + + if (!(IS_PORTABILITY_CASE)) { + g_free (new_pathname); + return(NULL); + } + + components = g_strsplit (new_pathname, "/", 0); + if (components == NULL) { + /* This shouldn't happen */ + g_free (new_pathname); + return(NULL); + } + + while(components[num_components] != NULL) { + num_components++; + } + g_free (new_pathname); + + if (num_components == 0){ + return NULL; + } + + + new_components = (gchar **)g_new0 (gchar **, num_components + 1); + + if (num_components > 1) { + if (strcmp (components[0], "") == 0) { + /* first component blank, so start at / */ + scanning = opendir ("/"); + if (scanning == NULL) { +#ifdef DEBUG + g_message ("%s: opendir 1 error: %s", __func__, + g_strerror (errno)); +#endif + g_strfreev (new_components); + g_strfreev (components); + return(NULL); + } + + new_components[component++] = g_strdup (""); + } else { + DIR *current; + gchar *entry; + + current = opendir ("."); + if (current == NULL) { +#ifdef DEBUG + g_message ("%s: opendir 2 error: %s", __func__, + g_strerror (errno)); +#endif + g_strfreev (new_components); + g_strfreev (components); + return(NULL); + } + + entry = find_in_dir (current, components[0]); + if (entry == NULL) { + g_strfreev (new_components); + g_strfreev (components); + return(NULL); + } + + scanning = opendir (entry); + if (scanning == NULL) { +#ifdef DEBUG + g_message ("%s: opendir 3 error: %s", __func__, + g_strerror (errno)); +#endif + g_free (entry); + g_strfreev (new_components); + g_strfreev (components); + return(NULL); + } + + new_components[component++] = entry; + } + } else { + if (last_exists) { + if (strcmp (components[0], "") == 0) { + /* First and only component blank */ + new_components[component++] = g_strdup (""); + } else { + DIR *current; + gchar *entry; + + current = opendir ("."); + if (current == NULL) { +#ifdef DEBUG + g_message ("%s: opendir 4 error: %s", + __func__, + g_strerror (errno)); +#endif + g_strfreev (new_components); + g_strfreev (components); + return(NULL); + } + + entry = find_in_dir (current, components[0]); + if (entry == NULL) { + g_strfreev (new_components); + g_strfreev (components); + return(NULL); + } + + new_components[component++] = entry; + } + } else { + new_components[component++] = g_strdup (components[0]); + } + } + +#ifdef DEBUG + g_message ("%s: Got first entry: [%s]\n", __func__, new_components[0]); +#endif + + g_assert (component == 1); + + for(; component < num_components; component++) { + gchar *entry; + gchar *path_so_far; + + if (!last_exists && + component == num_components -1) { + entry = g_strdup (components[component]); + closedir (scanning); + } else { + entry = find_in_dir (scanning, components[component]); + if (entry == NULL) { + g_strfreev (new_components); + g_strfreev (components); + return(NULL); + } + } + + new_components[component] = entry; + + if (component < num_components -1) { + path_so_far = g_strjoinv ("/", new_components); + + scanning = opendir (path_so_far); + g_free (path_so_far); + if (scanning == NULL) { + g_strfreev (new_components); + g_strfreev (components); + return(NULL); + } + } + } + + g_strfreev (components); + + new_pathname = g_strjoinv ("/", new_components); + +#ifdef DEBUG + g_message ("%s: pathname [%s] became [%s]\n", __func__, pathname, + new_pathname); +#endif + + g_strfreev (new_components); + + if ((last_exists && + access (new_pathname, F_OK) == 0) || + (!last_exists)) { + if (do_report && strcmp (pathname, new_pathname) != 0) + do_mono_profiler_iomap (report, pathname, new_pathname); + + return(new_pathname); + } + + g_free (new_pathname); + return(NULL); } +#endif