NaCl runtime fixes
[mono.git] / mono / io-layer / io.c
old mode 100644 (file)
new mode 100755 (executable)
index 1a300e4..a3e5ad1
@@ -329,6 +329,7 @@ static void _wapi_set_last_path_error_from_errno (const gchar *dir,
 static void file_close (gpointer handle, gpointer data)
 {
        struct _WapiHandle_file *file_handle = (struct _WapiHandle_file *)data;
+       int fd = file_handle->fd;
        
        DEBUG("%s: closing file handle %p [%s]", __func__, handle,
                  file_handle->filename);
@@ -341,7 +342,7 @@ static void file_close (gpointer handle, gpointer data)
        if (file_handle->share_info)
                _wapi_handle_share_release (file_handle->share_info);
        
-       close (GPOINTER_TO_UINT(handle));
+       close (fd);
 }
 
 static WapiFileType file_getfiletype(void)
@@ -355,8 +356,7 @@ static gboolean file_read(gpointer handle, gpointer buffer,
 {
        struct _WapiHandle_file *file_handle;
        gboolean ok;
-       int fd = GPOINTER_TO_UINT(handle);
-       int ret;
+       int fd, ret;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -367,6 +367,7 @@ static gboolean file_read(gpointer handle, gpointer buffer,
                return(FALSE);
        }
 
+       fd = file_handle->fd;
        if(bytesread!=NULL) {
                *bytesread=0;
        }
@@ -407,9 +408,8 @@ static gboolean file_write(gpointer handle, gconstpointer buffer,
 {
        struct _WapiHandle_file *file_handle;
        gboolean ok;
-       int ret;
+       int ret, fd;
        off_t current_pos = 0;
-       int fd = GPOINTER_TO_UINT(handle);
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -419,6 +419,8 @@ static gboolean file_write(gpointer handle, gconstpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+
+       fd = file_handle->fd;
        
        if(byteswritten!=NULL) {
                *byteswritten=0;
@@ -483,8 +485,7 @@ static gboolean file_flush(gpointer handle)
 {
        struct _WapiHandle_file *file_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -495,6 +496,8 @@ static gboolean file_flush(gpointer handle)
                return(FALSE);
        }
 
+       fd = file_handle->fd;
+
        if(!(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
                DEBUG("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
@@ -521,9 +524,8 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
        struct _WapiHandle_file *file_handle;
        gboolean ok;
        off_t offset, newpos;
-       int whence;
+       int whence, fd;
        guint32 ret;
-       int fd = GPOINTER_TO_UINT(handle);
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -534,6 +536,8 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
                return(INVALID_SET_FILE_POINTER);
        }
        
+       fd = file_handle->fd;
+
        if(!(file_handle->fileaccess & GENERIC_READ) &&
           !(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
@@ -622,8 +626,7 @@ static gboolean file_setendoffile(gpointer handle)
        gboolean ok;
        struct stat statbuf;
        off_t size, pos;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -633,6 +636,7 @@ static gboolean file_setendoffile(gpointer handle)
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = file_handle->fd;
        
        if(!(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
@@ -704,6 +708,8 @@ 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
         */
@@ -718,6 +724,7 @@ static gboolean file_setendoffile(gpointer handle)
                _wapi_set_last_error_from_errno ();
                return(FALSE);
        }
+#endif
                
        return(TRUE);
 }
@@ -729,7 +736,7 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
        struct stat statbuf;
        guint32 size;
        int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -739,6 +746,7 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
                SetLastError (ERROR_INVALID_HANDLE);
                return(INVALID_FILE_SIZE);
        }
+       fd = file_handle->fd;
        
        if(!(file_handle->fileaccess & GENERIC_READ) &&
           !(file_handle->fileaccess & GENERIC_WRITE) &&
@@ -814,8 +822,7 @@ static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
        gboolean ok;
        struct stat statbuf;
        guint64 create_ticks, access_ticks, write_ticks;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -825,6 +832,7 @@ static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = file_handle->fd;
 
        if(!(file_handle->fileaccess & GENERIC_READ) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
@@ -896,8 +904,7 @@ static gboolean file_setfiletime(gpointer handle,
        struct utimbuf utbuf;
        struct stat statbuf;
        guint64 access_ticks, write_ticks;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -907,6 +914,7 @@ static gboolean file_setfiletime(gpointer handle,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = file_handle->fd;
        
        if(!(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
@@ -989,12 +997,13 @@ static gboolean file_setfiletime(gpointer handle,
 static void console_close (gpointer handle, gpointer data)
 {
        struct _WapiHandle_file *console_handle = (struct _WapiHandle_file *)data;
+       int fd = console_handle->fd;
        
        DEBUG("%s: closing console handle %p", __func__, handle);
 
        g_free (console_handle->filename);
        
-       close (GPOINTER_TO_UINT(handle));
+       close (fd);
 }
 
 static WapiFileType console_getfiletype(void)
@@ -1008,9 +1017,8 @@ static gboolean console_read(gpointer handle, gpointer buffer,
 {
        struct _WapiHandle_file *console_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
-       
+       int ret, fd;
+
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
                                (gpointer *)&console_handle);
        if(ok==FALSE) {
@@ -1019,6 +1027,7 @@ static gboolean console_read(gpointer handle, gpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = console_handle->fd;
        
        if(bytesread!=NULL) {
                *bytesread=0;
@@ -1058,8 +1067,7 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
 {
        struct _WapiHandle_file *console_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
                                (gpointer *)&console_handle);
@@ -1069,6 +1077,7 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = console_handle->fd;
        
        if(byteswritten!=NULL) {
                *byteswritten=0;
@@ -1106,13 +1115,16 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
        return(TRUE);
 }
 
-static void pipe_close (gpointer handle, gpointer data G_GNUC_UNUSED)
+static void pipe_close (gpointer handle, gpointer data)
 {
+       struct _WapiHandle_file *pipe_handle = (struct _WapiHandle_file*)data;
+       int fd = pipe_handle->fd;
+
        DEBUG("%s: closing pipe handle %p", __func__, handle);
 
        /* No filename with pipe handles */
 
-       close(GPOINTER_TO_UINT(handle));
+       close (fd);
 }
 
 static WapiFileType pipe_getfiletype(void)
@@ -1126,9 +1138,8 @@ static gboolean pipe_read (gpointer handle, gpointer buffer,
 {
        struct _WapiHandle_file *pipe_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
-       
+       int ret, fd;
+
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
                                (gpointer *)&pipe_handle);
        if(ok==FALSE) {
@@ -1137,6 +1148,7 @@ static gboolean pipe_read (gpointer handle, gpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = pipe_handle->fd;
 
        if(bytesread!=NULL) {
                *bytesread=0;
@@ -1186,8 +1198,7 @@ static gboolean pipe_write(gpointer handle, gconstpointer buffer,
 {
        struct _WapiHandle_file *pipe_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
                                (gpointer *)&pipe_handle);
@@ -1197,6 +1208,7 @@ static gboolean pipe_write(gpointer handle, gconstpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = pipe_handle->fd;
        
        if(byteswritten!=NULL) {
                *byteswritten=0;
@@ -1503,6 +1515,13 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
                
                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_check (&statbuf, sharemode, fileaccess,
                         &file_handle.share_info, fd) == FALSE) {
@@ -1530,6 +1549,7 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
                //security, sizeof(WapiSecurityAttributes));
        }
        
+       file_handle.fd = fd;
        file_handle.fileaccess=fileaccess;
        file_handle.sharemode=sharemode;
        file_handle.attrs=attrs;
@@ -1847,7 +1867,9 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
        gchar *utf8_src, *utf8_dest;
        int src_fd, dest_fd;
        struct stat st, dest_st;
+       struct utimbuf dest_time;
        gboolean ret = TRUE;
+       int ret_utime;
        
        if(name==NULL) {
                DEBUG("%s: name is NULL", __func__);
@@ -1949,10 +1971,17 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
        if (!write_file (src_fd, dest_fd, &st, TRUE))
                ret = FALSE;
 
-       g_free (utf8_src);
-       g_free (utf8_dest);
        close (src_fd);
        close (dest_fd);
+       
+       dest_time.modtime = st.st_mtime;
+       dest_time.actime = st.st_atime;
+       ret_utime = utime (utf8_dest, &dest_time);
+       if (ret_utime == -1)
+               DEBUG ("%s: file [%s] utime failed: %s", __func__, utf8_dest, strerror(errno));
+       
+       g_free (utf8_src);
+       g_free (utf8_dest);
 
        return ret;
 }
@@ -2727,6 +2756,7 @@ retry:
                goto retry;
        }
 
+#ifndef __native_client__
        result = _wapi_lstat (filename, &linkbuf);
        if (result != 0) {
                DEBUG ("%s: lstat failed: %s", __func__, filename);
@@ -2734,6 +2764,7 @@ retry:
                g_free (filename);
                goto retry;
        }
+#endif
 
        utf8_filename = mono_utf8_from_external (filename);
        if (utf8_filename == NULL) {
@@ -2757,7 +2788,11 @@ 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
 
        _wapi_time_t_to_filetime (create_time, &find_data->ftCreationTime);
        _wapi_time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
@@ -2980,14 +3015,20 @@ guint32 GetFileAttributes (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);
 
@@ -3184,6 +3225,12 @@ extern guint32 GetCurrentDirectory (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 ((char*)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*/
@@ -3197,6 +3244,7 @@ extern guint32 GetCurrentDirectory (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;
@@ -3278,6 +3326,7 @@ gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
        
        /* filedes[0] is open for reading, filedes[1] for writing */
 
+       pipe_read_handle.fd = filedes [0];
        pipe_read_handle.fileaccess = GENERIC_READ;
        read_handle = _wapi_handle_new_fd (WAPI_HANDLE_PIPE, filedes[0],
                                           &pipe_read_handle);
@@ -3290,6 +3339,7 @@ gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
                return(FALSE);
        }
        
+       pipe_write_handle.fd = filedes [1];
        pipe_write_handle.fileaccess = GENERIC_WRITE;
        write_handle = _wapi_handle_new_fd (WAPI_HANDLE_PIPE, filedes[1],
                                            &pipe_write_handle);
@@ -4105,8 +4155,12 @@ GetDriveTypeFromPath (const gchar *utf8_root_path_name)
                if (strcmp (*(splitted + 1), utf8_root_path_name) == 0 ||
                    (strcmp (*(splitted + 1), "/") == 0 && strlen (utf8_root_path_name) == 0)) {
                        drive_type = _wapi_get_drive_type (*(splitted + 2));
-                       g_strfreev (splitted);
-                       break;
+                       /* it is possible this path might be mounted again with
+                          a known type...keep looking */
+                       if (drive_type != DRIVE_UNKNOWN) {
+                               g_strfreev (splitted);
+                               break;
+                       }
                }
 
                g_strfreev (splitted);
@@ -4146,7 +4200,7 @@ guint32 GetDriveType(const gunichar2 *root_path_name)
        return (drive_type);
 }
 
-static const gchar*
+static gchar*
 get_fstypename (gchar *utfpath)
 {
 #if defined (PLATFORM_MACOSX) || defined (__linux__)
@@ -4157,12 +4211,12 @@ get_fstypename (gchar *utfpath)
        if (statfs (utfpath, &stat) == -1)
                return NULL;
 #if PLATFORM_MACOSX
-       return stat.f_fstypename;
+       return g_strdup (stat.f_fstypename);
 #else
        current = &_wapi_drive_types[0];
        while (current->drive_type != DRIVE_UNKNOWN) {
                if (stat.f_type == current->fstypeid)
-                       return current->fstype;
+                       return g_strdup (current->fstype);
                current++;
        }
        return NULL;
@@ -4178,7 +4232,7 @@ gboolean
 GetVolumeInformation (const gunichar2 *path, gunichar2 *volumename, int volumesize, int *outserial, int *maxcomp, int *fsflags, gunichar2 *fsbuffer, int fsbuffersize)
 {
        gchar *utfpath;
-       const gchar *fstypename;
+       gchar *fstypename;
        gboolean status = FALSE;
        glong len;
        
@@ -4196,6 +4250,7 @@ GetVolumeInformation (const gunichar2 *path, gunichar2 *volumename, int volumesi
                }
                if (ret != NULL)
                        g_free (ret);
+               g_free (fstypename);
        }
        g_free (utfpath);
        return status;