2 * io-portability.c: Optional filename mangling to try to cope with
3 * badly-written non-portable windows apps
6 * Dick Porter (dick@ximian.com)
8 * Copyright (c) 2006 Novell, Inc.
20 #include <sys/types.h>
28 #include <mono/io-layer/mono-mutex.h>
29 #include <mono/io-layer/error.h>
30 #include <mono/io-layer/wapi_glob.h>
31 #include <mono/io-layer/io-portability.h>
32 #include <mono/utils/mono-io-portability.h>
36 int _wapi_open (const char *pathname
, int flags
, mode_t mode
)
39 gchar
*located_filename
;
41 if (flags
& O_CREAT
) {
42 located_filename
= mono_portability_find_file (pathname
, FALSE
);
43 if (located_filename
== NULL
) {
44 fd
= open (pathname
, flags
, mode
);
46 fd
= open (located_filename
, flags
, mode
);
47 g_free (located_filename
);
50 fd
= open (pathname
, flags
, mode
);
52 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
54 int saved_errno
= errno
;
55 located_filename
= mono_portability_find_file (pathname
, TRUE
);
57 if (located_filename
== NULL
) {
62 fd
= open (located_filename
, flags
, mode
);
63 g_free (located_filename
);
71 int _wapi_access (const char *pathname
, int mode
)
75 ret
= access (pathname
, mode
);
77 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
79 int saved_errno
= errno
;
80 gchar
*located_filename
= mono_portability_find_file (pathname
, TRUE
);
82 if (located_filename
== NULL
) {
87 ret
= access (located_filename
, mode
);
88 g_free (located_filename
);
94 int _wapi_chmod (const char *pathname
, mode_t mode
)
98 ret
= chmod (pathname
, mode
);
100 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
101 IS_PORTABILITY_SET
) {
102 int saved_errno
= errno
;
103 gchar
*located_filename
= mono_portability_find_file (pathname
, TRUE
);
105 if (located_filename
== NULL
) {
110 ret
= chmod (located_filename
, mode
);
111 g_free (located_filename
);
117 int _wapi_utime (const char *filename
, const struct utimbuf
*buf
)
121 ret
= utime (filename
, buf
);
124 IS_PORTABILITY_SET
) {
125 int saved_errno
= errno
;
126 gchar
*located_filename
= mono_portability_find_file (filename
, TRUE
);
128 if (located_filename
== NULL
) {
133 ret
= utime (located_filename
, buf
);
134 g_free (located_filename
);
140 int _wapi_unlink (const char *pathname
)
144 ret
= unlink (pathname
);
146 (errno
== ENOENT
|| errno
== ENOTDIR
|| errno
== EISDIR
) &&
147 IS_PORTABILITY_SET
) {
148 int saved_errno
= errno
;
149 gchar
*located_filename
= mono_portability_find_file (pathname
, TRUE
);
151 if (located_filename
== NULL
) {
156 ret
= unlink (located_filename
);
157 g_free (located_filename
);
163 int _wapi_rename (const char *oldpath
, const char *newpath
)
166 gchar
*located_newpath
= mono_portability_find_file (newpath
, FALSE
);
168 if (located_newpath
== NULL
) {
169 ret
= rename (oldpath
, newpath
);
171 ret
= rename (oldpath
, located_newpath
);
174 (errno
== EISDIR
|| errno
== ENAMETOOLONG
||
175 errno
== ENOENT
|| errno
== ENOTDIR
|| errno
== EXDEV
) &&
176 IS_PORTABILITY_SET
) {
177 int saved_errno
= errno
;
178 gchar
*located_oldpath
= mono_portability_find_file (oldpath
, TRUE
);
180 if (located_oldpath
== NULL
) {
181 g_free (located_oldpath
);
182 g_free (located_newpath
);
188 ret
= rename (located_oldpath
, located_newpath
);
189 g_free (located_oldpath
);
191 g_free (located_newpath
);
197 int _wapi_stat (const char *path
, struct stat
*buf
)
201 ret
= stat (path
, buf
);
203 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
204 IS_PORTABILITY_SET
) {
205 int saved_errno
= errno
;
206 gchar
*located_filename
= mono_portability_find_file (path
, TRUE
);
208 if (located_filename
== NULL
) {
213 ret
= stat (located_filename
, buf
);
214 g_free (located_filename
);
220 int _wapi_lstat (const char *path
, struct stat
*buf
)
224 ret
= lstat (path
, buf
);
226 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
227 IS_PORTABILITY_SET
) {
228 int saved_errno
= errno
;
229 gchar
*located_filename
= mono_portability_find_file (path
, TRUE
);
231 if (located_filename
== NULL
) {
236 ret
= lstat (located_filename
, buf
);
237 g_free (located_filename
);
243 int _wapi_mkdir (const char *pathname
, mode_t mode
)
246 gchar
*located_filename
= mono_portability_find_file (pathname
, FALSE
);
248 if (located_filename
== NULL
) {
249 ret
= mkdir (pathname
, mode
);
251 ret
= mkdir (located_filename
, mode
);
252 g_free (located_filename
);
258 int _wapi_rmdir (const char *pathname
)
262 ret
= rmdir (pathname
);
264 (errno
== ENOENT
|| errno
== ENOTDIR
|| errno
== ENAMETOOLONG
) &&
265 IS_PORTABILITY_SET
) {
266 int saved_errno
= errno
;
267 gchar
*located_filename
= mono_portability_find_file (pathname
, TRUE
);
269 if (located_filename
== NULL
) {
274 ret
= rmdir (located_filename
);
275 g_free (located_filename
);
281 int _wapi_chdir (const char *path
)
287 (errno
== ENOENT
|| errno
== ENOTDIR
|| errno
== ENAMETOOLONG
) &&
288 IS_PORTABILITY_SET
) {
289 int saved_errno
= errno
;
290 gchar
*located_filename
= mono_portability_find_file (path
, TRUE
);
292 if (located_filename
== NULL
) {
297 ret
= chdir (located_filename
);
298 g_free (located_filename
);
304 gchar
*_wapi_basename (const gchar
*filename
)
306 gchar
*new_filename
= g_strdup (filename
), *ret
;
308 if (IS_PORTABILITY_SET
) {
309 g_strdelimit (new_filename
, "\\", '/');
312 if (IS_PORTABILITY_DRIVE
&&
313 g_ascii_isalpha (new_filename
[0]) &&
314 (new_filename
[1] == ':')) {
315 int len
= strlen (new_filename
);
317 g_memmove (new_filename
, new_filename
+ 2, len
- 2);
318 new_filename
[len
- 2] = '\0';
321 ret
= g_path_get_basename (new_filename
);
322 g_free (new_filename
);
327 gchar
*_wapi_dirname (const gchar
*filename
)
329 gchar
*new_filename
= g_strdup (filename
), *ret
;
331 if (IS_PORTABILITY_SET
) {
332 g_strdelimit (new_filename
, "\\", '/');
335 if (IS_PORTABILITY_DRIVE
&&
336 g_ascii_isalpha (new_filename
[0]) &&
337 (new_filename
[1] == ':')) {
338 int len
= strlen (new_filename
);
340 g_memmove (new_filename
, new_filename
+ 2, len
- 2);
341 new_filename
[len
- 2] = '\0';
344 ret
= g_path_get_dirname (new_filename
);
345 g_free (new_filename
);
350 GDir
*_wapi_g_dir_open (const gchar
*path
, guint flags
, GError
**error
)
354 ret
= g_dir_open (path
, flags
, error
);
356 ((*error
)->code
== G_FILE_ERROR_NOENT
||
357 (*error
)->code
== G_FILE_ERROR_NOTDIR
||
358 (*error
)->code
== G_FILE_ERROR_NAMETOOLONG
) &&
359 IS_PORTABILITY_SET
) {
360 gchar
*located_filename
= mono_portability_find_file (path
, TRUE
);
361 GError
*tmp_error
= NULL
;
363 if (located_filename
== NULL
) {
367 ret
= g_dir_open (located_filename
, flags
, &tmp_error
);
368 g_free (located_filename
);
369 if (tmp_error
== NULL
) {
370 g_clear_error (error
);
379 file_compare (gconstpointer a
, gconstpointer b
)
381 gchar
*astr
= *(gchar
**) a
;
382 gchar
*bstr
= *(gchar
**) b
;
384 return strcmp (astr
, bstr
);
388 get_errno_from_g_file_error (gint error
)
392 case G_FILE_ERROR_ACCES
:
397 case G_FILE_ERROR_NAMETOOLONG
:
398 error
= ENAMETOOLONG
;
402 case G_FILE_ERROR_NOENT
:
407 case G_FILE_ERROR_NOTDIR
:
412 case G_FILE_ERROR_NXIO
:
417 case G_FILE_ERROR_NODEV
:
422 case G_FILE_ERROR_ROFS
:
427 case G_FILE_ERROR_TXTBSY
:
432 case G_FILE_ERROR_FAULT
:
437 case G_FILE_ERROR_LOOP
:
442 case G_FILE_ERROR_NOSPC
:
447 case G_FILE_ERROR_NOMEM
:
452 case G_FILE_ERROR_MFILE
:
457 case G_FILE_ERROR_NFILE
:
462 case G_FILE_ERROR_BADF
:
467 case G_FILE_ERROR_INVAL
:
472 case G_FILE_ERROR_PIPE
:
477 case G_FILE_ERROR_AGAIN
:
482 case G_FILE_ERROR_INTR
:
487 case G_FILE_ERROR_IO
:
492 case G_FILE_ERROR_PERM
:
496 case G_FILE_ERROR_FAILED
:
497 error
= ERROR_INVALID_PARAMETER
;
504 /* scandir using glib */
505 gint
_wapi_io_scandir (const gchar
*dirname
, const gchar
*pattern
,
508 GError
*error
= NULL
;
512 wapi_glob_t glob_buf
;
515 dir
= _wapi_g_dir_open (dirname
, 0, &error
);
517 /* g_dir_open returns ENOENT on directories on which we don't
518 * have read/x permission */
519 gint errnum
= get_errno_from_g_file_error (error
->code
);
520 g_error_free (error
);
521 if (errnum
== ENOENT
&&
522 !_wapi_access (dirname
, F_OK
) &&
523 _wapi_access (dirname
, R_OK
|X_OK
)) {
531 if (IS_PORTABILITY_CASE
) {
532 flags
= WAPI_GLOB_IGNORECASE
;
535 result
= _wapi_glob (dir
, pattern
, flags
, &glob_buf
);
536 if (g_str_has_suffix (pattern
, ".*")) {
537 /* Special-case the patterns ending in '.*', as
538 * windows also matches entries with no extension with
541 * TODO: should this be a MONO_IOMAP option?
543 gchar
*pattern2
= g_strndup (pattern
, strlen (pattern
) - 2);
547 result2
= _wapi_glob (dir
, pattern2
, flags
| WAPI_GLOB_APPEND
| WAPI_GLOB_UNIQUE
, &glob_buf
);
557 if (glob_buf
.gl_pathc
== 0) {
559 } else if (result
!= 0) {
563 names
= g_ptr_array_new ();
564 for (i
= 0; i
< glob_buf
.gl_pathc
; i
++) {
565 g_ptr_array_add (names
, g_strdup (glob_buf
.gl_pathv
[i
]));
568 _wapi_globfree (&glob_buf
);
572 g_ptr_array_sort (names
, file_compare
);
573 g_ptr_array_set_size (names
, result
+ 1);
575 *namelist
= (gchar
**) g_ptr_array_free (names
, FALSE
);
577 g_ptr_array_free (names
, TRUE
);