NaCl runtime fixes
[mono.git] / mono / utils / mono-path.c
1 /*
2  * mono-path.c: Routines for handling path names.
3  * 
4  * Authors:
5  *      Gonzalo Paniagua Javier (gonzalo@novell.com)
6  *      Miguel de Icaza (miguel@novell.com)
7  *
8  * (C) 2006 Novell, Inc.  http://www.novell.com
9  *
10  */
11 #include <config.h>
12 #include <glib.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19 /* This is only needed for the mono_path_canonicalize code, MAXSYMLINKS, could be moved */
20 #ifdef HAVE_SYS_PARAM_H
21 #include <sys/param.h>
22 #endif
23
24 #include "mono-path.h"
25
26 /* Embedded systems lack MAXSYMLINKS */
27 #ifndef MAXSYMLINKS
28 #define MAXSYMLINKS 3
29 #endif
30
31 /* Resolves '..' and '.' references in a path. If the path provided is relative,
32  * it will be relative to the current directory */
33
34 /* For Native Client, the above is not true.  Since there is no getcwd we fill */
35 /* in the file being passed in relative to '.' and don't resolve it            */
36
37 /* There are a couple of tests for this method in mono/test/mono-path.cs */
38 gchar *
39 mono_path_canonicalize (const char *path)
40 {
41         gchar *abspath, *pos, *lastpos, *dest;
42         int backc;
43
44         if (g_path_is_absolute (path)) {
45                 abspath = g_strdup (path);
46         } else {
47                 gchar *tmpdir = g_get_current_dir ();
48                 abspath = g_build_filename (tmpdir, path, NULL);
49                 g_free (tmpdir);
50         }
51
52 #ifdef HOST_WIN32
53         g_strdelimit (abspath, "/", '\\');
54 #endif
55         abspath = g_strreverse (abspath);
56
57         backc = 0;
58         dest = lastpos = abspath;
59         pos = strchr (lastpos, G_DIR_SEPARATOR);
60
61         while (pos != NULL) {
62                 int len = pos - lastpos;
63                 if (len == 1 && lastpos [0] == '.') {
64                         // nop
65                 } else if (len == 2 && lastpos [0] == '.' && lastpos [1] == '.') {
66                         backc++;
67                 } else if (len > 0) {
68                         if (backc > 0) {
69                                 backc--;
70                         } else {
71                                 if (dest != lastpos) 
72                                         /* The two strings can overlap */
73                                         memmove (dest, lastpos, len + 1);
74                                 dest += len + 1;
75                         }
76                 }
77                 lastpos = pos + 1;
78                 pos = strchr (lastpos, G_DIR_SEPARATOR);
79         }
80
81 #ifdef HOST_WIN32
82         /* Avoid removing the first '\' for UNC paths. We must make sure that it's indeed an UNC path
83         by checking if the \\ pair happens exactly at the end of the string.
84         */
85         if (*(lastpos-1) == G_DIR_SEPARATOR && *(lastpos-2) == G_DIR_SEPARATOR && *lastpos == 0)
86                 lastpos = lastpos-1;
87 #endif
88         
89         if (dest != lastpos) strcpy (dest, lastpos);
90         
91         g_strreverse (abspath);
92
93         /* We strip away all trailing dir separators. This is not correct for the root directory,
94          * since we'll return an empty string, so re-append a dir separator if there is none in the
95          * result */
96         if (strchr (abspath, G_DIR_SEPARATOR) == NULL) {
97                 int len = strlen (abspath);
98                 abspath = g_realloc (abspath, len + 2);
99                 abspath [len] = G_DIR_SEPARATOR;
100                 abspath [len+1] = 0;
101         }
102
103         return abspath;
104 }
105
106 /*
107  * This ensures that the path that we store points to the final file
108  * not a path to a symlink.
109  */
110 #if !defined(PLATFORM_NO_SYMLINKS)
111 static gchar *
112 resolve_symlink (const char *path)
113 {
114         char *p, *concat, *dir;
115         char buffer [PATH_MAX+1];
116         int n, iterations = 0;
117
118         p = g_strdup (path);
119         do {
120                 iterations++;
121                 n = readlink (p, buffer, sizeof (buffer)-1);
122                 if (n < 0){
123                         char *copy = p;
124                         p = mono_path_canonicalize (copy);
125                         g_free (copy);
126                         return p;
127                 }
128                 
129                 buffer [n] = 0;
130                 if (!g_path_is_absolute (buffer)) {
131                         dir = g_path_get_dirname (p);
132                         concat = g_build_filename (dir, buffer, NULL);
133                         g_free (dir);
134                 } else {
135                         concat = g_strdup (buffer);
136                 }
137                 g_free (p);
138                 p = mono_path_canonicalize (concat);
139                 g_free (concat);
140         } while (iterations < MAXSYMLINKS);
141
142         return p;
143 }
144 #endif
145
146 gchar *
147 mono_path_resolve_symlinks (const char *path)
148 {
149 #if defined(PLATFORM_NO_SYMLINKS)
150         return mono_path_canonicalize (path);
151 #else
152         gchar **split = g_strsplit (path, G_DIR_SEPARATOR_S, -1);
153         gchar *p = g_strdup ("");
154         int i;
155
156         for (i = 0; split [i] != NULL; i++) {
157                 gchar *tmp = NULL;
158
159                 // resolve_symlink of "" goes into canonicalize which resolves to cwd
160                 if (strcmp (split [i], "") != 0) {
161                         tmp = g_strdup_printf ("%s%s", p, split [i]);
162                         g_free (p);
163                         p = resolve_symlink (tmp);
164                         g_free (tmp);
165                 }
166
167                 if (split [i+1] != NULL) {
168                         tmp = g_strdup_printf ("%s%s", p, G_DIR_SEPARATOR_S);
169                         g_free (p);
170                         p = tmp;
171                 }
172         }
173
174         g_strfreev (split);
175         return p;
176 #endif
177 }
178