8 #include <mono/utils/mono-io-portability.h>
10 #ifdef DISABLE_PORTABILITY
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
);