8 #include <mono/utils/mono-io-portability.h>
11 int __mono_io_portability_helpers = PORTABILITY_NONE;
14 mono_portability_helpers_init (void)
19 mono_portability_find_file (const gchar *pathname, gboolean last_exists)
21 g_assert_not_reached();
29 int __mono_io_portability_helpers = PORTABILITY_UNKNOWN;
31 void mono_portability_helpers_init (void)
35 if (__mono_io_portability_helpers != PORTABILITY_UNKNOWN)
38 __mono_io_portability_helpers = PORTABILITY_NONE;
40 env = g_getenv ("MONO_IOMAP");
42 /* parse the environment setting and set up some vars
45 gchar **options = g_strsplit (env, ":", 0);
48 if (options == NULL) {
49 /* This shouldn't happen */
53 for (i = 0; options[i] != NULL; i++) {
55 g_message ("%s: Setting option [%s]", __func__,
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 |
70 /* Returns newly allocated string, or NULL on failure */
71 static gchar *find_in_dir (DIR *current, const gchar *name)
76 g_message ("%s: looking for [%s]\n", __func__, name);
79 while((entry = readdir (current)) != NULL) {
81 g_message ("%s: found [%s]\n", __func__, entry->d_name);
84 if (!g_ascii_strcasecmp (name, entry->d_name)) {
88 g_message ("%s: matched [%s] to [%s]\n", __func__,
92 ret = g_strdup (entry->d_name);
99 g_message ("%s: returning NULL\n", __func__);
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;
115 if (IS_PORTABILITY_NONE) {
119 new_pathname = g_strdup (pathname);
122 g_message ("%s: Finding [%s] last_exists: %s\n", __func__, pathname,
123 last_exists?"TRUE":"FALSE");
127 access (new_pathname, F_OK) == 0) {
129 g_message ("%s: Found it without doing anything\n", __func__);
131 return(new_pathname);
134 /* First turn '\' into '/' and strip any drive letters */
135 g_strdelimit (new_pathname, "\\", '/');
138 g_message ("%s: Fixed slashes, now have [%s]\n", __func__,
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';
151 g_message ("%s: Stripped drive letter, now looking for [%s]\n",
152 __func__, new_pathname);
156 len = strlen (new_pathname);
157 if (len > 1 && new_pathname [len - 1] == '/') {
158 new_pathname [len - 1] = 0;
160 g_message ("%s: requested name had a trailing /, rewritten to '%s'\n",
161 __func__, new_pathname);
166 access (new_pathname, F_OK) == 0) {
168 g_message ("%s: Found it\n", __func__);
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);
183 components = g_strsplit (new_pathname, "/", 0);
184 if (components == NULL) {
185 /* This shouldn't happen */
186 g_free (new_pathname);
190 while(components[num_components] != NULL) {
193 g_free (new_pathname);
195 if (num_components == 0){
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) {
208 g_message ("%s: opendir 1 error: %s", __func__,
211 g_strfreev (new_components);
212 g_strfreev (components);
216 new_components[component++] = g_strdup ("");
221 current = opendir (".");
222 if (current == NULL) {
224 g_message ("%s: opendir 2 error: %s", __func__,
227 g_strfreev (new_components);
228 g_strfreev (components);
232 entry = find_in_dir (current, components[0]);
234 g_strfreev (new_components);
235 g_strfreev (components);
239 scanning = opendir (entry);
240 if (scanning == NULL) {
242 g_message ("%s: opendir 3 error: %s", __func__,
246 g_strfreev (new_components);
247 g_strfreev (components);
251 new_components[component++] = entry;
255 if (strcmp (components[0], "") == 0) {
256 /* First and only component blank */
257 new_components[component++] = g_strdup ("");
262 current = opendir (".");
263 if (current == NULL) {
265 g_message ("%s: opendir 4 error: %s",
269 g_strfreev (new_components);
270 g_strfreev (components);
274 entry = find_in_dir (current, components[0]);
276 g_strfreev (new_components);
277 g_strfreev (components);
281 new_components[component++] = entry;
284 new_components[component++] = g_strdup (components[0]);
289 g_message ("%s: Got first entry: [%s]\n", __func__, new_components[0]);
292 g_assert (component == 1);
294 for(; component < num_components; component++) {
299 component == num_components -1) {
300 entry = g_strdup (components[component]);
303 entry = find_in_dir (scanning, components[component]);
305 g_strfreev (new_components);
306 g_strfreev (components);
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);
326 g_strfreev (components);
328 new_pathname = g_strjoinv ("/", new_components);
331 g_message ("%s: pathname [%s] became [%s]\n", __func__, pathname,
335 g_strfreev (new_components);
338 access (new_pathname, F_OK) == 0) ||
340 return(new_pathname);
343 g_free (new_pathname);