NaCl runtime fixes
[mono.git] / mono / utils / mono-path.c
index c2a510ad586b8cf80933e2d33c088fefddcea75f..0a443aa41f76c1a977ac108b5e0a4a635651ae6e 100644 (file)
 #include <errno.h>
 #include <string.h>
 #include <stdlib.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 /* This is only needed for the mono_path_canonicalize code, MAXSYMLINKS, could be moved */
+#ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
+#endif
 
 #include "mono-path.h"
 
+/* Embedded systems lack MAXSYMLINKS */
+#ifndef MAXSYMLINKS
+#define MAXSYMLINKS 3
+#endif
+
 /* Resolves '..' and '.' references in a path. If the path provided is relative,
  * it will be relative to the current directory */
+
+/* For Native Client, the above is not true.  Since there is no getcwd we fill */
+/* in the file being passed in relative to '.' and don't resolve it            */
+
+/* There are a couple of tests for this method in mono/test/mono-path.cs */
 gchar *
 mono_path_canonicalize (const char *path)
 {
@@ -35,6 +49,9 @@ mono_path_canonicalize (const char *path)
                g_free (tmpdir);
        }
 
+#ifdef HOST_WIN32
+       g_strdelimit (abspath, "/", '\\');
+#endif
        abspath = g_strreverse (abspath);
 
        backc = 0;
@@ -60,21 +77,40 @@ mono_path_canonicalize (const char *path)
                lastpos = pos + 1;
                pos = strchr (lastpos, G_DIR_SEPARATOR);
        }
+
+#ifdef HOST_WIN32
+       /* Avoid removing the first '\' for UNC paths. We must make sure that it's indeed an UNC path
+       by checking if the \\ pair happens exactly at the end of the string.
+       */
+       if (*(lastpos-1) == G_DIR_SEPARATOR && *(lastpos-2) == G_DIR_SEPARATOR && *lastpos == 0)
+               lastpos = lastpos-1;
+#endif
        
        if (dest != lastpos) strcpy (dest, lastpos);
-       return g_strreverse (abspath);
+       
+       g_strreverse (abspath);
+
+       /* We strip away all trailing dir separators. This is not correct for the root directory,
+        * since we'll return an empty string, so re-append a dir separator if there is none in the
+        * result */
+       if (strchr (abspath, G_DIR_SEPARATOR) == NULL) {
+               int len = strlen (abspath);
+               abspath = g_realloc (abspath, len + 2);
+               abspath [len] = G_DIR_SEPARATOR;
+               abspath [len+1] = 0;
+       }
+
+       return abspath;
 }
 
 /*
  * This ensures that the path that we store points to the final file
  * not a path to a symlink.
  */
-gchar *
-mono_path_resolve_symlinks (const char *path)
+#if !defined(PLATFORM_NO_SYMLINKS)
+static gchar *
+resolve_symlink (const char *path)
 {
-#if PLATFORM_WIN32
-       return mono_path_canonicalize (path);
-#else
        char *p, *concat, *dir;
        char buffer [PATH_MAX+1];
        int n, iterations = 0;
@@ -103,6 +139,39 @@ mono_path_resolve_symlinks (const char *path)
                g_free (concat);
        } while (iterations < MAXSYMLINKS);
 
+       return p;
+}
+#endif
+
+gchar *
+mono_path_resolve_symlinks (const char *path)
+{
+#if defined(PLATFORM_NO_SYMLINKS)
+       return mono_path_canonicalize (path);
+#else
+       gchar **split = g_strsplit (path, G_DIR_SEPARATOR_S, -1);
+       gchar *p = g_strdup ("");
+       int i;
+
+       for (i = 0; split [i] != NULL; i++) {
+               gchar *tmp = NULL;
+
+               // resolve_symlink of "" goes into canonicalize which resolves to cwd
+               if (strcmp (split [i], "") != 0) {
+                       tmp = g_strdup_printf ("%s%s", p, split [i]);
+                       g_free (p);
+                       p = resolve_symlink (tmp);
+                       g_free (tmp);
+               }
+
+               if (split [i+1] != NULL) {
+                       tmp = g_strdup_printf ("%s%s", p, G_DIR_SEPARATOR_S);
+                       g_free (p);
+                       p = tmp;
+               }
+       }
+
+       g_strfreev (split);
        return p;
 #endif
 }