2009-02-25 Zoltan Varga <vargaz@gmail.com>
[mono-debugger.git] / mono / utils / mono-io-portability.c
bloba1aa6a853b566b68418332aab1fd7648257ac502
1 #include "config.h"
3 #include <string.h>
4 #ifdef HAVE_UNISTD_H
5 #include <unistd.h>
6 #endif
7 #include <errno.h>
8 #include <mono/utils/mono-io-portability.h>
10 #ifdef DISABLE_PORTABILITY
11 int __mono_io_portability_helpers = PORTABILITY_NONE;
13 void
14 mono_portability_helpers_init (void)
18 gchar *
19 mono_portability_find_file (const gchar *pathname, gboolean last_exists)
21 g_assert_not_reached();
22 return NULL;
25 #else
27 #include <dirent.h>
29 int __mono_io_portability_helpers = PORTABILITY_UNKNOWN;
31 void mono_portability_helpers_init (void)
33 const gchar *env;
35 if (__mono_io_portability_helpers != PORTABILITY_UNKNOWN)
36 return;
38 __mono_io_portability_helpers = PORTABILITY_NONE;
40 env = g_getenv ("MONO_IOMAP");
41 if (env != NULL) {
42 /* parse the environment setting and set up some vars
43 * here
45 gchar **options = g_strsplit (env, ":", 0);
46 int i;
48 if (options == NULL) {
49 /* This shouldn't happen */
50 return;
53 for (i = 0; options[i] != NULL; i++) {
54 #ifdef DEBUG
55 g_message ("%s: Setting option [%s]", __func__,
56 options[i]);
57 #endif
58 if (!strncasecmp (options[i], "drive", 5)) {
59 __mono_io_portability_helpers |= PORTABILITY_DRIVE;
60 } else if (!strncasecmp (options[i], "case", 4)) {
61 __mono_io_portability_helpers |= PORTABILITY_CASE;
62 } else if (!strncasecmp (options[i], "all", 3)) {
63 __mono_io_portability_helpers |= (PORTABILITY_DRIVE |
64 PORTABILITY_CASE);
70 /* Returns newly allocated string, or NULL on failure */
71 static gchar *find_in_dir (DIR *current, const gchar *name)
73 struct dirent *entry;
75 #ifdef DEBUG
76 g_message ("%s: looking for [%s]\n", __func__, name);
77 #endif
79 while((entry = readdir (current)) != NULL) {
80 #ifdef DEBUGX
81 g_message ("%s: found [%s]\n", __func__, entry->d_name);
82 #endif
84 if (!g_ascii_strcasecmp (name, entry->d_name)) {
85 char *ret;
87 #ifdef DEBUG
88 g_message ("%s: matched [%s] to [%s]\n", __func__,
89 entry->d_name, name);
90 #endif
92 ret = g_strdup (entry->d_name);
93 closedir (current);
94 return ret;
98 #ifdef DEBUG
99 g_message ("%s: returning NULL\n", __func__);
100 #endif
102 closedir (current);
104 return(NULL);
107 /* Returns newly-allocated string or NULL on failure */
108 gchar *mono_portability_find_file (const gchar *pathname, gboolean last_exists)
110 gchar *new_pathname, **components, **new_components;
111 int num_components = 0, component = 0;
112 DIR *scanning = NULL;
113 size_t len;
115 if (IS_PORTABILITY_NONE) {
116 return(NULL);
119 new_pathname = g_strdup (pathname);
121 #ifdef DEBUG
122 g_message ("%s: Finding [%s] last_exists: %s\n", __func__, pathname,
123 last_exists?"TRUE":"FALSE");
124 #endif
126 if (last_exists &&
127 access (new_pathname, F_OK) == 0) {
128 #ifdef DEBUG
129 g_message ("%s: Found it without doing anything\n", __func__);
130 #endif
131 return(new_pathname);
134 /* First turn '\' into '/' and strip any drive letters */
135 g_strdelimit (new_pathname, "\\", '/');
137 #ifdef DEBUG
138 g_message ("%s: Fixed slashes, now have [%s]\n", __func__,
139 new_pathname);
140 #endif
142 if (IS_PORTABILITY_DRIVE &&
143 g_ascii_isalpha (new_pathname[0]) &&
144 (new_pathname[1] == ':')) {
145 int len = strlen (new_pathname);
147 g_memmove (new_pathname, new_pathname+2, len - 2);
148 new_pathname[len - 2] = '\0';
150 #ifdef DEBUG
151 g_message ("%s: Stripped drive letter, now looking for [%s]\n",
152 __func__, new_pathname);
153 #endif
156 len = strlen (new_pathname);
157 if (len > 1 && new_pathname [len - 1] == '/') {
158 new_pathname [len - 1] = 0;
159 #ifdef DEBUG
160 g_message ("%s: requested name had a trailing /, rewritten to '%s'\n",
161 __func__, new_pathname);
162 #endif
165 if (last_exists &&
166 access (new_pathname, F_OK) == 0) {
167 #ifdef DEBUG
168 g_message ("%s: Found it\n", __func__);
169 #endif
171 return(new_pathname);
174 /* OK, have to work harder. Take each path component in turn
175 * and do a case-insensitive directory scan for it
178 if (!(IS_PORTABILITY_CASE)) {
179 g_free (new_pathname);
180 return(NULL);
183 components = g_strsplit (new_pathname, "/", 0);
184 if (components == NULL) {
185 /* This shouldn't happen */
186 g_free (new_pathname);
187 return(NULL);
190 while(components[num_components] != NULL) {
191 num_components++;
193 g_free (new_pathname);
195 if (num_components == 0){
196 return NULL;
200 new_components = (gchar **)g_new0 (gchar **, num_components + 1);
202 if (num_components > 1) {
203 if (strcmp (components[0], "") == 0) {
204 /* first component blank, so start at / */
205 scanning = opendir ("/");
206 if (scanning == NULL) {
207 #ifdef DEBUG
208 g_message ("%s: opendir 1 error: %s", __func__,
209 g_strerror (errno));
210 #endif
211 g_strfreev (new_components);
212 g_strfreev (components);
213 return(NULL);
216 new_components[component++] = g_strdup ("");
217 } else {
218 DIR *current;
219 gchar *entry;
221 current = opendir (".");
222 if (current == NULL) {
223 #ifdef DEBUG
224 g_message ("%s: opendir 2 error: %s", __func__,
225 g_strerror (errno));
226 #endif
227 g_strfreev (new_components);
228 g_strfreev (components);
229 return(NULL);
232 entry = find_in_dir (current, components[0]);
233 if (entry == NULL) {
234 g_strfreev (new_components);
235 g_strfreev (components);
236 return(NULL);
239 scanning = opendir (entry);
240 if (scanning == NULL) {
241 #ifdef DEBUG
242 g_message ("%s: opendir 3 error: %s", __func__,
243 g_strerror (errno));
244 #endif
245 g_free (entry);
246 g_strfreev (new_components);
247 g_strfreev (components);
248 return(NULL);
251 new_components[component++] = entry;
253 } else {
254 if (last_exists) {
255 if (strcmp (components[0], "") == 0) {
256 /* First and only component blank */
257 new_components[component++] = g_strdup ("");
258 } else {
259 DIR *current;
260 gchar *entry;
262 current = opendir (".");
263 if (current == NULL) {
264 #ifdef DEBUG
265 g_message ("%s: opendir 4 error: %s",
266 __func__,
267 g_strerror (errno));
268 #endif
269 g_strfreev (new_components);
270 g_strfreev (components);
271 return(NULL);
274 entry = find_in_dir (current, components[0]);
275 if (entry == NULL) {
276 g_strfreev (new_components);
277 g_strfreev (components);
278 return(NULL);
281 new_components[component++] = entry;
283 } else {
284 new_components[component++] = g_strdup (components[0]);
288 #ifdef DEBUG
289 g_message ("%s: Got first entry: [%s]\n", __func__, new_components[0]);
290 #endif
292 g_assert (component == 1);
294 for(; component < num_components; component++) {
295 gchar *entry;
296 gchar *path_so_far;
298 if (!last_exists &&
299 component == num_components -1) {
300 entry = g_strdup (components[component]);
301 closedir (scanning);
302 } else {
303 entry = find_in_dir (scanning, components[component]);
304 if (entry == NULL) {
305 g_strfreev (new_components);
306 g_strfreev (components);
307 return(NULL);
311 new_components[component] = entry;
313 if (component < num_components -1) {
314 path_so_far = g_strjoinv ("/", new_components);
316 scanning = opendir (path_so_far);
317 g_free (path_so_far);
318 if (scanning == NULL) {
319 g_strfreev (new_components);
320 g_strfreev (components);
321 return(NULL);
326 g_strfreev (components);
328 new_pathname = g_strjoinv ("/", new_components);
330 #ifdef DEBUG
331 g_message ("%s: pathname [%s] became [%s]\n", __func__, pathname,
332 new_pathname);
333 #endif
335 g_strfreev (new_components);
337 if ((last_exists &&
338 access (new_pathname, F_OK) == 0) ||
339 (!last_exists)) {
340 return(new_pathname);
343 g_free (new_pathname);
344 return(NULL);
348 #endif