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>
35 int _wapi_open (const char *pathname
, int flags
, mode_t mode
)
38 gchar
*located_filename
;
40 if (flags
& O_CREAT
) {
41 located_filename
= mono_portability_find_file (pathname
, FALSE
);
42 if (located_filename
== NULL
) {
43 fd
= open (pathname
, flags
, mode
);
45 fd
= open (located_filename
, flags
, mode
);
46 g_free (located_filename
);
49 fd
= open (pathname
, flags
, mode
);
51 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
53 int saved_errno
= errno
;
54 located_filename
= mono_portability_find_file (pathname
, TRUE
);
56 if (located_filename
== NULL
) {
61 fd
= open (located_filename
, flags
, mode
);
62 g_free (located_filename
);
70 int _wapi_access (const char *pathname
, int mode
)
74 ret
= access (pathname
, mode
);
76 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
78 int saved_errno
= errno
;
79 gchar
*located_filename
= mono_portability_find_file (pathname
, TRUE
);
81 if (located_filename
== NULL
) {
86 ret
= access (located_filename
, mode
);
87 g_free (located_filename
);
93 int _wapi_chmod (const char *pathname
, mode_t mode
)
97 ret
= chmod (pathname
, mode
);
99 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
100 IS_PORTABILITY_SET
) {
101 int saved_errno
= errno
;
102 gchar
*located_filename
= mono_portability_find_file (pathname
, TRUE
);
104 if (located_filename
== NULL
) {
109 ret
= chmod (located_filename
, mode
);
110 g_free (located_filename
);
116 int _wapi_utime (const char *filename
, const struct utimbuf
*buf
)
120 ret
= utime (filename
, buf
);
123 IS_PORTABILITY_SET
) {
124 int saved_errno
= errno
;
125 gchar
*located_filename
= mono_portability_find_file (filename
, TRUE
);
127 if (located_filename
== NULL
) {
132 ret
= utime (located_filename
, buf
);
133 g_free (located_filename
);
139 int _wapi_unlink (const char *pathname
)
143 ret
= unlink (pathname
);
145 (errno
== ENOENT
|| errno
== ENOTDIR
|| errno
== EISDIR
) &&
146 IS_PORTABILITY_SET
) {
147 int saved_errno
= errno
;
148 gchar
*located_filename
= mono_portability_find_file (pathname
, TRUE
);
150 if (located_filename
== NULL
) {
155 ret
= unlink (located_filename
);
156 g_free (located_filename
);
162 int _wapi_rename (const char *oldpath
, const char *newpath
)
165 gchar
*located_newpath
= mono_portability_find_file (newpath
, FALSE
);
167 if (located_newpath
== NULL
) {
168 ret
= rename (oldpath
, newpath
);
170 ret
= rename (oldpath
, located_newpath
);
173 (errno
== EISDIR
|| errno
== ENAMETOOLONG
||
174 errno
== ENOENT
|| errno
== ENOTDIR
|| errno
== EXDEV
) &&
175 IS_PORTABILITY_SET
) {
176 int saved_errno
= errno
;
177 gchar
*located_oldpath
= mono_portability_find_file (oldpath
, TRUE
);
179 if (located_oldpath
== NULL
) {
180 g_free (located_oldpath
);
181 g_free (located_newpath
);
187 ret
= rename (located_oldpath
, located_newpath
);
188 g_free (located_oldpath
);
190 g_free (located_newpath
);
196 int _wapi_stat (const char *path
, struct stat
*buf
)
200 ret
= stat (path
, buf
);
202 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
203 IS_PORTABILITY_SET
) {
204 int saved_errno
= errno
;
205 gchar
*located_filename
= mono_portability_find_file (path
, TRUE
);
207 if (located_filename
== NULL
) {
212 ret
= stat (located_filename
, buf
);
213 g_free (located_filename
);
219 int _wapi_lstat (const char *path
, struct stat
*buf
)
223 ret
= lstat (path
, buf
);
225 (errno
== ENOENT
|| errno
== ENOTDIR
) &&
226 IS_PORTABILITY_SET
) {
227 int saved_errno
= errno
;
228 gchar
*located_filename
= mono_portability_find_file (path
, TRUE
);
230 if (located_filename
== NULL
) {
235 ret
= lstat (located_filename
, buf
);
236 g_free (located_filename
);
242 int _wapi_mkdir (const char *pathname
, mode_t mode
)
245 gchar
*located_filename
= mono_portability_find_file (pathname
, FALSE
);
247 if (located_filename
== NULL
) {
248 ret
= mkdir (pathname
, mode
);
250 ret
= mkdir (located_filename
, mode
);
251 g_free (located_filename
);
257 int _wapi_rmdir (const char *pathname
)
261 ret
= rmdir (pathname
);
263 (errno
== ENOENT
|| errno
== ENOTDIR
|| errno
== ENAMETOOLONG
) &&
264 IS_PORTABILITY_SET
) {
265 int saved_errno
= errno
;
266 gchar
*located_filename
= mono_portability_find_file (pathname
, TRUE
);
268 if (located_filename
== NULL
) {
273 ret
= rmdir (located_filename
);
274 g_free (located_filename
);
280 int _wapi_chdir (const char *path
)
286 (errno
== ENOENT
|| errno
== ENOTDIR
|| errno
== ENAMETOOLONG
) &&
287 IS_PORTABILITY_SET
) {
288 int saved_errno
= errno
;
289 gchar
*located_filename
= mono_portability_find_file (path
, TRUE
);
291 if (located_filename
== NULL
) {
296 ret
= chdir (located_filename
);
297 g_free (located_filename
);
303 gchar
*_wapi_basename (const gchar
*filename
)
305 gchar
*new_filename
= g_strdup (filename
), *ret
;
307 if (IS_PORTABILITY_SET
) {
308 g_strdelimit (new_filename
, "\\", '/');
311 if (IS_PORTABILITY_DRIVE
&&
312 g_ascii_isalpha (new_filename
[0]) &&
313 (new_filename
[1] == ':')) {
314 int len
= strlen (new_filename
);
316 g_memmove (new_filename
, new_filename
+ 2, len
- 2);
317 new_filename
[len
- 2] = '\0';
320 ret
= g_path_get_basename (new_filename
);
321 g_free (new_filename
);
326 gchar
*_wapi_dirname (const gchar
*filename
)
328 gchar
*new_filename
= g_strdup (filename
), *ret
;
330 if (IS_PORTABILITY_SET
) {
331 g_strdelimit (new_filename
, "\\", '/');
334 if (IS_PORTABILITY_DRIVE
&&
335 g_ascii_isalpha (new_filename
[0]) &&
336 (new_filename
[1] == ':')) {
337 int len
= strlen (new_filename
);
339 g_memmove (new_filename
, new_filename
+ 2, len
- 2);
340 new_filename
[len
- 2] = '\0';
343 ret
= g_path_get_dirname (new_filename
);
344 g_free (new_filename
);
349 GDir
*_wapi_g_dir_open (const gchar
*path
, guint flags
, GError
**error
)
353 ret
= g_dir_open (path
, flags
, error
);
355 ((*error
)->code
== G_FILE_ERROR_NOENT
||
356 (*error
)->code
== G_FILE_ERROR_NOTDIR
||
357 (*error
)->code
== G_FILE_ERROR_NAMETOOLONG
) &&
358 IS_PORTABILITY_SET
) {
359 gchar
*located_filename
= mono_portability_find_file (path
, TRUE
);
360 GError
*tmp_error
= NULL
;
362 if (located_filename
== NULL
) {
366 ret
= g_dir_open (located_filename
, flags
, &tmp_error
);
367 g_free (located_filename
);
368 if (tmp_error
== NULL
) {
369 g_clear_error (error
);
378 file_compare (gconstpointer a
, gconstpointer b
)
380 gchar
*astr
= *(gchar
**) a
;
381 gchar
*bstr
= *(gchar
**) b
;
383 return strcmp (astr
, bstr
);
387 get_errno_from_g_file_error (gint error
)
391 case G_FILE_ERROR_ACCES
:
396 case G_FILE_ERROR_NAMETOOLONG
:
397 error
= ENAMETOOLONG
;
401 case G_FILE_ERROR_NOENT
:
406 case G_FILE_ERROR_NOTDIR
:
411 case G_FILE_ERROR_NXIO
:
416 case G_FILE_ERROR_NODEV
:
421 case G_FILE_ERROR_ROFS
:
426 case G_FILE_ERROR_TXTBSY
:
431 case G_FILE_ERROR_FAULT
:
436 case G_FILE_ERROR_LOOP
:
441 case G_FILE_ERROR_NOSPC
:
446 case G_FILE_ERROR_NOMEM
:
451 case G_FILE_ERROR_MFILE
:
456 case G_FILE_ERROR_NFILE
:
461 case G_FILE_ERROR_BADF
:
466 case G_FILE_ERROR_INVAL
:
471 case G_FILE_ERROR_PIPE
:
476 case G_FILE_ERROR_AGAIN
:
481 case G_FILE_ERROR_INTR
:
486 case G_FILE_ERROR_IO
:
491 case G_FILE_ERROR_PERM
:
495 case G_FILE_ERROR_FAILED
:
496 error
= ERROR_INVALID_PARAMETER
;
503 /* scandir using glib */
504 gint
_wapi_io_scandir (const gchar
*dirname
, const gchar
*pattern
,
507 GError
*error
= NULL
;
511 wapi_glob_t glob_buf
;
514 dir
= _wapi_g_dir_open (dirname
, 0, &error
);
516 /* g_dir_open returns ENOENT on directories on which we don't
517 * have read/x permission */
518 gint errnum
= get_errno_from_g_file_error (error
->code
);
519 g_error_free (error
);
520 if (errnum
== ENOENT
&&
521 !_wapi_access (dirname
, F_OK
) &&
522 _wapi_access (dirname
, R_OK
|X_OK
)) {
530 if (IS_PORTABILITY_CASE
) {
531 flags
= WAPI_GLOB_IGNORECASE
;
534 result
= _wapi_glob (dir
, pattern
, flags
, &glob_buf
);
535 if (g_str_has_suffix (pattern
, ".*")) {
536 /* Special-case the patterns ending in '.*', as
537 * windows also matches entries with no extension with
540 * TODO: should this be a MONO_IOMAP option?
542 gchar
*pattern2
= g_strndup (pattern
, strlen (pattern
) - 2);
546 result2
= _wapi_glob (dir
, pattern2
, flags
| WAPI_GLOB_APPEND
| WAPI_GLOB_UNIQUE
, &glob_buf
);
556 if (glob_buf
.gl_pathc
== 0) {
558 } else if (result
!= 0) {
562 names
= g_ptr_array_new ();
563 for (i
= 0; i
< glob_buf
.gl_pathc
; i
++) {
564 g_ptr_array_add (names
, g_strdup (glob_buf
.gl_pathv
[i
]));
567 _wapi_globfree (&glob_buf
);
571 g_ptr_array_sort (names
, file_compare
);
572 g_ptr_array_set_size (names
, result
+ 1);
574 *namelist
= (gchar
**) g_ptr_array_free (names
, FALSE
);
576 g_ptr_array_free (names
, TRUE
);