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>
25 #include <mono/io-layer/mono-mutex.h>
26 #include <mono/io-layer/error.h>
27 #include <mono/io-layer/wapi_glob.h>
28 #include <mono/io-layer/io-portability.h>
29 #include <mono/utils/mono-io-portability.h>
33 int _wapi_open (const char *pathname, int flags, mode_t mode)
36 gchar *located_filename;
38 if (flags & O_CREAT) {
39 located_filename = mono_portability_find_file (pathname, FALSE);
40 if (located_filename == NULL) {
41 fd = open (pathname, flags, mode);
43 fd = open (located_filename, flags, mode);
44 g_free (located_filename);
47 fd = open (pathname, flags, mode);
49 (errno == ENOENT || errno == ENOTDIR) &&
51 int saved_errno = errno;
52 located_filename = mono_portability_find_file (pathname, TRUE);
54 if (located_filename == NULL) {
59 fd = open (located_filename, flags, mode);
60 g_free (located_filename);
68 int _wapi_access (const char *pathname, int mode)
72 ret = access (pathname, mode);
74 (errno == ENOENT || errno == ENOTDIR) &&
76 int saved_errno = errno;
77 gchar *located_filename = mono_portability_find_file (pathname, TRUE);
79 if (located_filename == NULL) {
84 ret = access (located_filename, mode);
85 g_free (located_filename);
91 int _wapi_chmod (const char *pathname, mode_t mode)
95 ret = chmod (pathname, mode);
97 (errno == ENOENT || errno == ENOTDIR) &&
99 int saved_errno = errno;
100 gchar *located_filename = mono_portability_find_file (pathname, TRUE);
102 if (located_filename == NULL) {
107 ret = chmod (located_filename, mode);
108 g_free (located_filename);
114 int _wapi_utime (const char *filename, const struct utimbuf *buf)
118 ret = utime (filename, buf);
121 IS_PORTABILITY_SET) {
122 int saved_errno = errno;
123 gchar *located_filename = mono_portability_find_file (filename, TRUE);
125 if (located_filename == NULL) {
130 ret = utime (located_filename, buf);
131 g_free (located_filename);
137 int _wapi_unlink (const char *pathname)
141 ret = unlink (pathname);
143 (errno == ENOENT || errno == ENOTDIR || errno == EISDIR) &&
144 IS_PORTABILITY_SET) {
145 int saved_errno = errno;
146 gchar *located_filename = mono_portability_find_file (pathname, TRUE);
148 if (located_filename == NULL) {
153 ret = unlink (located_filename);
154 g_free (located_filename);
160 int _wapi_rename (const char *oldpath, const char *newpath)
163 gchar *located_newpath = mono_portability_find_file (newpath, FALSE);
165 if (located_newpath == NULL) {
166 ret = rename (oldpath, newpath);
168 ret = rename (oldpath, located_newpath);
171 (errno == EISDIR || errno == ENAMETOOLONG ||
172 errno == ENOENT || errno == ENOTDIR || errno == EXDEV) &&
173 IS_PORTABILITY_SET) {
174 int saved_errno = errno;
175 gchar *located_oldpath = mono_portability_find_file (oldpath, TRUE);
177 if (located_oldpath == NULL) {
178 g_free (located_oldpath);
179 g_free (located_newpath);
185 ret = rename (located_oldpath, located_newpath);
186 g_free (located_oldpath);
188 g_free (located_newpath);
194 int _wapi_stat (const char *path, struct stat *buf)
198 ret = stat (path, buf);
200 (errno == ENOENT || errno == ENOTDIR) &&
201 IS_PORTABILITY_SET) {
202 int saved_errno = errno;
203 gchar *located_filename = mono_portability_find_file (path, TRUE);
205 if (located_filename == NULL) {
210 ret = stat (located_filename, buf);
211 g_free (located_filename);
217 int _wapi_lstat (const char *path, struct stat *buf)
221 ret = lstat (path, buf);
223 (errno == ENOENT || errno == ENOTDIR) &&
224 IS_PORTABILITY_SET) {
225 int saved_errno = errno;
226 gchar *located_filename = mono_portability_find_file (path, TRUE);
228 if (located_filename == NULL) {
233 ret = lstat (located_filename, buf);
234 g_free (located_filename);
240 int _wapi_mkdir (const char *pathname, mode_t mode)
243 gchar *located_filename = mono_portability_find_file (pathname, FALSE);
245 if (located_filename == NULL) {
246 ret = mkdir (pathname, mode);
248 ret = mkdir (located_filename, mode);
249 g_free (located_filename);
255 int _wapi_rmdir (const char *pathname)
259 ret = rmdir (pathname);
261 (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) &&
262 IS_PORTABILITY_SET) {
263 int saved_errno = errno;
264 gchar *located_filename = mono_portability_find_file (pathname, TRUE);
266 if (located_filename == NULL) {
271 ret = rmdir (located_filename);
272 g_free (located_filename);
278 int _wapi_chdir (const char *path)
284 (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) &&
285 IS_PORTABILITY_SET) {
286 int saved_errno = errno;
287 gchar *located_filename = mono_portability_find_file (path, TRUE);
289 if (located_filename == NULL) {
294 ret = chdir (located_filename);
295 g_free (located_filename);
301 gchar *_wapi_basename (const gchar *filename)
303 gchar *new_filename = g_strdup (filename), *ret;
305 g_strdelimit (new_filename, "\\", '/');
307 if (IS_PORTABILITY_DRIVE &&
308 g_ascii_isalpha (new_filename[0]) &&
309 (new_filename[1] == ':')) {
310 int len = strlen (new_filename);
312 g_memmove (new_filename, new_filename + 2, len - 2);
313 new_filename[len - 2] = '\0';
316 ret = g_path_get_basename (new_filename);
317 g_free (new_filename);
322 gchar *_wapi_dirname (const gchar *filename)
324 gchar *new_filename = g_strdup (filename), *ret;
326 g_strdelimit (new_filename, "\\", '/');
328 if (IS_PORTABILITY_DRIVE &&
329 g_ascii_isalpha (new_filename[0]) &&
330 (new_filename[1] == ':')) {
331 int len = strlen (new_filename);
333 g_memmove (new_filename, new_filename + 2, len - 2);
334 new_filename[len - 2] = '\0';
337 ret = g_path_get_dirname (new_filename);
338 g_free (new_filename);
343 GDir *_wapi_g_dir_open (const gchar *path, guint flags, GError **error)
347 ret = g_dir_open (path, flags, error);
349 ((*error)->code == G_FILE_ERROR_NOENT ||
350 (*error)->code == G_FILE_ERROR_NOTDIR ||
351 (*error)->code == G_FILE_ERROR_NAMETOOLONG) &&
352 IS_PORTABILITY_SET) {
353 gchar *located_filename = mono_portability_find_file (path, TRUE);
354 GError *tmp_error = NULL;
356 if (located_filename == NULL) {
360 ret = g_dir_open (located_filename, flags, &tmp_error);
361 g_free (located_filename);
362 if (tmp_error == NULL) {
363 g_clear_error (error);
372 file_compare (gconstpointer a, gconstpointer b)
374 gchar *astr = *(gchar **) a;
375 gchar *bstr = *(gchar **) b;
377 return strcmp (astr, bstr);
381 get_errno_from_g_file_error (gint error)
385 case G_FILE_ERROR_ACCES:
390 case G_FILE_ERROR_NAMETOOLONG:
391 error = ENAMETOOLONG;
395 case G_FILE_ERROR_NOENT:
400 case G_FILE_ERROR_NOTDIR:
405 case G_FILE_ERROR_NXIO:
410 case G_FILE_ERROR_NODEV:
415 case G_FILE_ERROR_ROFS:
420 case G_FILE_ERROR_TXTBSY:
425 case G_FILE_ERROR_FAULT:
430 case G_FILE_ERROR_LOOP:
435 case G_FILE_ERROR_NOSPC:
440 case G_FILE_ERROR_NOMEM:
445 case G_FILE_ERROR_MFILE:
450 case G_FILE_ERROR_NFILE:
455 case G_FILE_ERROR_BADF:
460 case G_FILE_ERROR_INVAL:
465 case G_FILE_ERROR_PIPE:
470 case G_FILE_ERROR_AGAIN:
475 case G_FILE_ERROR_INTR:
480 case G_FILE_ERROR_IO:
485 case G_FILE_ERROR_PERM:
489 case G_FILE_ERROR_FAILED:
490 error = ERROR_INVALID_PARAMETER;
497 /* scandir using glib */
498 gint _wapi_io_scandir (const gchar *dirname, const gchar *pattern,
501 GError *error = NULL;
505 wapi_glob_t glob_buf;
508 dir = _wapi_g_dir_open (dirname, 0, &error);
510 /* g_dir_open returns ENOENT on directories on which we don't
511 * have read/x permission */
512 gint errnum = get_errno_from_g_file_error (error->code);
513 g_error_free (error);
514 if (errnum == ENOENT &&
515 !_wapi_access (dirname, F_OK) &&
516 _wapi_access (dirname, R_OK|X_OK)) {
524 if (IS_PORTABILITY_CASE) {
525 flags = WAPI_GLOB_IGNORECASE;
528 result = _wapi_glob (dir, pattern, flags, &glob_buf);
529 if (g_str_has_suffix (pattern, ".*")) {
530 /* Special-case the patterns ending in '.*', as
531 * windows also matches entries with no extension with
534 * TODO: should this be a MONO_IOMAP option?
536 gchar *pattern2 = g_strndup (pattern, strlen (pattern) - 2);
540 result2 = _wapi_glob (dir, pattern2, flags | WAPI_GLOB_APPEND | WAPI_GLOB_UNIQUE, &glob_buf);
550 if (glob_buf.gl_pathc == 0) {
552 } else if (result != 0) {
556 names = g_ptr_array_new ();
557 for (i = 0; i < glob_buf.gl_pathc; i++) {
558 g_ptr_array_add (names, g_strdup (glob_buf.gl_pathv[i]));
561 _wapi_globfree (&glob_buf);
565 g_ptr_array_sort (names, file_compare);
566 g_ptr_array_set_size (names, result + 1);
568 *namelist = (gchar **) g_ptr_array_free (names, FALSE);
570 g_ptr_array_free (names, TRUE);