[runtime] Update comment with link to Linux Kernel fix.
[mono.git] / mono / metadata / w32file-unix.c
index cb744f785fd5a61bda9e49dd93b22fa53086300b..8c97b06cc8c9aaa91add0272f64f3ec381417f60 100644 (file)
@@ -1,3 +1,6 @@
+/**
+ * \file
+ */
 
 #include <config.h>
 #include <glib.h>
@@ -611,7 +614,7 @@ get_errno_from_g_file_error (gint error)
 #ifdef EINTR
        case G_FILE_ERROR_INTR: return EINTR;
 #endif
-#ifdef EWIO
+#ifdef EIO
        case G_FILE_ERROR_IO: return EIO;
 #endif
 #ifdef EPERM
@@ -718,11 +721,6 @@ _wapi_io_scandir (const gchar *dirname, const gchar *pattern, gchar ***namelist)
 static gboolean
 _wapi_lock_file_region (gint fd, off_t offset, off_t length)
 {
-#if defined(__native_client__)
-       printf("WARNING: %s: fcntl() not available on Native Client!\n", __func__);
-       // behave as below -- locks are not available
-       return TRUE;
-#else
        struct flock lock_data;
        gint ret;
 
@@ -763,16 +761,11 @@ _wapi_lock_file_region (gint fd, off_t offset, off_t length)
        }
 
        return TRUE;
-#endif /* __native_client__ */
 }
 
 static gboolean
 _wapi_unlock_file_region (gint fd, off_t offset, off_t length)
 {
-#if defined(__native_client__)
-       printf("WARNING: %s: fcntl() not available on Native Client!\n", __func__);
-       return TRUE;
-#else
        struct flock lock_data;
        gint ret;
 
@@ -808,7 +801,6 @@ _wapi_unlock_file_region (gint fd, off_t offset, off_t length)
        }
 
        return TRUE;
-#endif /* __native_client__ */
 }
 
 static void file_close (gpointer handle, gpointer data);
@@ -1526,8 +1518,6 @@ static gboolean file_setendoffile(gpointer handle)
        }
 #endif
 
-/* Native Client has no ftruncate function, even in standalone sel_ldr. */
-#ifndef __native_client__
        /* always truncate, because the extend write() adds an extra
         * byte to the end of the file
         */
@@ -1544,7 +1534,6 @@ static gboolean file_setendoffile(gpointer handle)
                _wapi_set_last_error_from_errno ();
                return(FALSE);
        }
-#endif
                
        return(TRUE);
 }
@@ -2404,13 +2393,6 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode
                
                return(INVALID_HANDLE_VALUE);
        }
-#ifdef __native_client__
-       /* Workaround: Native Client currently returns the same fake inode
-        * for all files, so do a simple hash on the filename so we don't
-        * use the same share info for each file.
-        */
-       statbuf.st_ino = g_str_hash(filename);
-#endif
 
        if (share_allows_open (&statbuf, sharemode, fileaccess,
                         &file_handle.share_info) == FALSE) {
@@ -2515,7 +2497,6 @@ gboolean mono_w32file_delete(const gunichar2 *name)
        gchar *filename;
        gint retval;
        gboolean ret = FALSE;
-       guint32 attrs;
 #if 0
        struct stat statbuf;
        FileShare *shareinfo;
@@ -2536,14 +2517,6 @@ gboolean mono_w32file_delete(const gunichar2 *name)
                return(FALSE);
        }
 
-       attrs = mono_w32file_get_attributes (name);
-       if (attrs == INVALID_FILE_ATTRIBUTES) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file attributes error", __func__);
-               /* Error set by mono_w32file_get_attributes() */
-               g_free (filename);
-               return(FALSE);
-       }
-
 #if 0
        /* Check to make sure sharing allows us to open the file for
         * writing.  See bug 323389.
@@ -2571,6 +2544,19 @@ gboolean mono_w32file_delete(const gunichar2 *name)
        retval = _wapi_unlink (filename);
        
        if (retval == -1) {
+               /* On linux, calling unlink on an non-existing file in a read-only mount will fail with EROFS.
+                * The expected behavior is for this function to return FALSE and not trigger an exception.
+                * To work around this behavior, we stat the file on failure.
+                *
+                * This was supposedly fixed on kernel 3.0 [1] but we could reproduce it with Ubuntu 16.04 which has kernel 4.4.
+                * We can't remove this workaround until the early 2020's when most Android deviced will have a fix.
+                * [1] https://github.com/torvalds/linux/commit/50338b889dc504c69e0cb316ac92d1b9e51f3c8a
+                */
+               if (errno == EROFS) {
+                       MonoIOStat stat;
+                       if (mono_w32file_get_attributes_ex (name, &stat)) //The file exists, so must be due the RO file system
+                               errno = EROFS;
+               }
                _wapi_set_last_path_error_from_errno (NULL, filename);
        } else {
                ret = TRUE;
@@ -2994,7 +2980,6 @@ _wapi_stdhandle_create (gint fd, const gchar *name)
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating standard handle type %s, fd %d", __func__, name, fd);
 
-#if !defined(__native_client__)
        /* Check if fd is valid */
        do {
                flags = fcntl(fd, F_GETFL);
@@ -3025,13 +3010,6 @@ _wapi_stdhandle_create (gint fd, const gchar *name)
                file_handle.fileaccess = 0;
                break;
        }
-#else
-       /*
-        * fcntl will return -1 in nacl, as there is no real file system API.
-        * Yet, standard streams are available.
-        */
-       file_handle.fileaccess = (fd == STDIN_FILENO) ? GENERIC_READ : GENERIC_WRITE;
-#endif
 
        file_handle.fd = fd;
        file_handle.filename = g_strdup(name);
@@ -3108,9 +3086,6 @@ mono_w32file_get_std_handle (gint stdhandle)
                        mono_w32error_set_last (ERROR_NO_MORE_FILES);
                        goto done;
                }
-       } else {
-               /* Add a reference to this handle */
-               mono_w32handle_ref (handle);
        }
        
   done:
@@ -3538,7 +3513,6 @@ retry:
                goto retry;
        }
 
-#ifndef __native_client__
        result = _wapi_lstat (filename, &linkbuf);
        if (result != 0) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lstat failed: %s", __func__, filename);
@@ -3546,7 +3520,6 @@ retry:
                g_free (filename);
                goto retry;
        }
-#endif
 
        utf8_filename = mono_utf8_from_external (filename);
        if (utf8_filename == NULL) {
@@ -3570,11 +3543,7 @@ retry:
        else
                create_time = buf.st_ctime;
        
-#ifdef __native_client__
-       find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, NULL);
-#else
        find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, &linkbuf);
-#endif
 
        time_t_to_filetime (create_time, &find_data->ftCreationTime);
        time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
@@ -3748,7 +3717,7 @@ mono_w32file_get_attributes (const gunichar2 *name)
        }
 
        result = _wapi_stat (utf8_name, &buf);
-       if (result == -1 && errno == ENOENT) {
+       if (result == -1 && (errno == ENOENT || errno == ELOOP)) {
                /* Might be a dangling symlink... */
                result = _wapi_lstat (utf8_name, &buf);
        }
@@ -3759,20 +3728,14 @@ mono_w32file_get_attributes (const gunichar2 *name)
                return (INVALID_FILE_ATTRIBUTES);
        }
 
-#ifndef __native_client__
        result = _wapi_lstat (utf8_name, &linkbuf);
        if (result != 0) {
                _wapi_set_last_path_error_from_errno (NULL, utf8_name);
                g_free (utf8_name);
                return (INVALID_FILE_ATTRIBUTES);
        }
-#endif
        
-#ifdef __native_client__
-       ret = _wapi_stat_to_file_attributes (utf8_name, &buf, NULL);
-#else
        ret = _wapi_stat_to_file_attributes (utf8_name, &buf, &linkbuf);
-#endif
        
        g_free (utf8_name);
 
@@ -3917,12 +3880,6 @@ mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
        glong count;
        gsize bytes;
 
-#ifdef __native_client__
-       gchar *path = g_get_current_dir ();
-       if (length < strlen(path) + 1 || path == NULL)
-               return 0;
-       memcpy (buffer, path, strlen(path) + 1);
-#else
        if (getcwd ((gchar*)buffer, length) == NULL) {
                if (errno == ERANGE) { /*buffer length is not big enough */ 
                        gchar *path = g_get_current_dir (); /*FIXME g_get_current_dir doesn't work with broken paths and calling it just to know the path length is silly*/
@@ -3936,7 +3893,6 @@ mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
                _wapi_set_last_error_from_errno ();
                return 0;
        }
-#endif
 
        utf16_path = mono_unicode_from_external ((gchar*)buffer, &bytes);
        count = (bytes/2)+1;
@@ -4928,7 +4884,7 @@ mono_w32file_get_drive_type(const gunichar2 *root_path_name)
        return (drive_type);
 }
 
-#if defined (PLATFORM_MACOSX) || defined (__linux__) || defined(PLATFORM_BSD) || defined(__native_client__) || defined(__FreeBSD_kernel__) || defined(__HAIKU__)
+#if defined (PLATFORM_MACOSX) || defined (__linux__) || defined(PLATFORM_BSD) || defined(__FreeBSD_kernel__) || defined(__HAIKU__)
 static gchar*
 get_fstypename (gchar *utfpath)
 {
@@ -5075,7 +5031,7 @@ mono_w32file_init (void)
 /*     mono_w32handle_register_capabilities (MONO_W32HANDLE_CONSOLE, */
 /*                                         MONO_W32HANDLE_CAP_WAIT); */
 
-       if (g_getenv ("MONO_STRICT_IO_EMULATION"))
+       if (g_hasenv ("MONO_STRICT_IO_EMULATION"))
                lock_while_writing = TRUE;
 }