Merge pull request #1529 from alistair/xmlreader_read_to_next_sibling_bug
[mono.git] / mono / metadata / file-mmap-posix.c
index eb69f5aa334e5b5039ca56e0451c4ee042ab2560..27fe27be4ec02c5a8e62c71c9a74af5e668611b2 100644 (file)
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/mono-mmap.h>
 
-enum {
-       MMAP_KIND_FILE = 1,
-       MMAP_KIND_MEMORY = 2    
-};
-
 typedef struct {
        int kind;
        int ref_count;
-       gint64 capacity;
+       size_t capacity;
        char *name;
-} Handle;
-
-typedef struct {
-       Handle handle;
        int fd;
-} FileHandle;
-
-typedef struct {
-       Handle handle;
-       void *address;
-       size_t length;
-} MemoryHandle;
+} MmapHandle;
 
 typedef struct {
        void *address;
        void *free_handle;
-       int kind;
        size_t length;
-} MmapHandle;
+} MmapInstance;
 
 enum {
        BAD_CAPACITY_FOR_FILE_BACKED = 1,
@@ -97,8 +81,10 @@ enum {
        MMAP_FILE_ACCESS_READ_WRITE_EXECUTE = 5,
 };
 
-#ifndef DEFFILEMODE
-#define DEFFILEMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
+#ifdef DEFFILEMODE
+#define DEFAULT_FILEMODE DEFFILEMODE
+#else
+#define DEFAULT_FILEMODE 0666
 #endif
 
 static int mmap_init_state;
@@ -242,7 +228,7 @@ open_file_map (MonoString *path, int input_fd, int mode, gint64 *capacity, int a
 {
        struct stat buf;
        char *c_path = path ? mono_string_to_utf8 (path) : NULL;
-       FileHandle *handle = NULL;
+       MmapHandle *handle = NULL;
        int result, fd;
 
        if (path)
@@ -285,7 +271,7 @@ open_file_map (MonoString *path, int input_fd, int mode, gint64 *capacity, int a
        }
 
        if (path) //FIXME use io portability?
-               fd = open (c_path, file_mode_to_unix (mode) | access_mode_to_unix (access), DEFFILEMODE);
+               fd = open (c_path, file_mode_to_unix (mode) | access_mode_to_unix (access), DEFAULT_FILEMODE);
        else
                fd = dup (input_fd);
 
@@ -300,10 +286,9 @@ open_file_map (MonoString *path, int input_fd, int mode, gint64 *capacity, int a
                int unused G_GNUC_UNUSED = ftruncate (fd, (off_t)*capacity);
        }
 
-       handle = g_new0 (FileHandle, 1);
-       handle->handle.kind = MMAP_KIND_FILE;
-       handle->handle.ref_count = 1;
-       handle->handle.capacity = *capacity;
+       handle = g_new0 (MmapHandle, 1);
+       handle->ref_count = 1;
+       handle->capacity = *capacity;
        handle->fd = fd;
 
 done:
@@ -311,11 +296,12 @@ done:
        return (void*)handle;
 }
 
+#define MONO_ANON_FILE_TEMPLATE "/mono.anonmap.XXXXXXXXX"
 static void*
 open_memory_map (MonoString *mapName, int mode, gint64 *capacity, int access, int options, int *error)
 {
        char *c_mapName;
-       MemoryHandle *handle;
+       MmapHandle *handle;
        if (*capacity <= 1) {
                *error = CAPACITY_MUST_BE_POSITIVE;
                return NULL;
@@ -329,31 +315,57 @@ open_memory_map (MonoString *mapName, int mode, gint64 *capacity, int access, in
        c_mapName = mono_string_to_utf8 (mapName);
 
        named_regions_lock ();
-       handle = (MemoryHandle*)g_hash_table_lookup (named_regions, c_mapName);
+       handle = (MmapHandle*)g_hash_table_lookup (named_regions, c_mapName);
        if (handle) {
-               if (mode == FILE_MODE_CREATE_NEW)
+               if (mode == FILE_MODE_CREATE_NEW) {
                        *error = FILE_ALREADY_EXISTS;
+                       goto done;
+               }
 
-               handle->handle.ref_count++;
+               handle->ref_count++;
                //XXX should we ftruncate if the file is smaller than capacity?
        } else {
-               if (mode == FILE_MODE_OPEN)
-                       *error = FILE_NOT_FOUND;
+               int fd;
+               char *file_name;
+               const char *tmp_dir;
+               int unused G_GNUC_UNUSED, alloc_size;
 
+               if (mode == FILE_MODE_OPEN) {
+                       *error = FILE_NOT_FOUND;
+                       goto done;
+               }
                *capacity = align_up_to_page_size (*capacity);
 
-               handle = g_new0 (MemoryHandle, 1);
-               handle->handle.kind = MMAP_KIND_MEMORY;
-               handle->handle.ref_count = 1;
-               handle->handle.capacity = *capacity;
-               handle->handle.name = g_strdup (c_mapName);
+               tmp_dir = g_get_tmp_dir ();
+               alloc_size = strlen (tmp_dir) + strlen (MONO_ANON_FILE_TEMPLATE) + 1;
+               if (alloc_size > 1024) {//rather fail that stack overflow
+                       *error = COULD_NOT_MAP_MEMORY;
+                       goto done;
+               }
+               file_name = alloca (alloc_size);
+               strcpy (file_name, tmp_dir);
+               strcat (file_name, MONO_ANON_FILE_TEMPLATE);
+
+               fd = mkstemp (file_name);
+               if (fd == -1) {
+                       *error = COULD_NOT_MAP_MEMORY;
+                       goto done;
+               }
+
+               unlink (file_name);
+               unused = ftruncate (fd, (off_t)*capacity);
+
+               handle = g_new0 (MmapHandle, 1);
+               handle->ref_count = 1;
+               handle->capacity = *capacity;
+               handle->fd = fd;
+               handle->name = g_strdup (c_mapName);
+
+               g_hash_table_insert (named_regions, handle->name, handle);
 
-               //FIXME compute RWX from access
-               handle->address = mono_valloc (NULL, (size_t)*capacity, MONO_MMAP_READ | MONO_MMAP_WRITE | MONO_MMAP_PRIVATE | MONO_MMAP_ANON);
-               handle->length = (size_t)*capacity;
-               g_hash_table_insert (named_regions, handle->handle.name, handle);
        }
 
+done:
        named_regions_unlock ();
 
        g_free (c_mapName);
@@ -370,69 +382,66 @@ mono_mmap_open_file (MonoString *path, int mode, MonoString *mapName, gint64 *ca
                return open_file_map (path, -1, mode, capacity, access, options, error);
 
        if (path) {
-               FileHandle *file_handle;
+               MmapHandle *handle;
                char *c_mapName = mono_string_to_utf8 (mapName);
 
                named_regions_lock ();
-               file_handle = (FileHandle*)g_hash_table_lookup (named_regions, c_mapName);
-               if (file_handle) {
+               handle = (MmapHandle*)g_hash_table_lookup (named_regions, c_mapName);
+               if (handle) {
                        *error = FILE_ALREADY_EXISTS;
-                       file_handle = NULL;
+                       handle = NULL;
                } else {
-                       file_handle = open_file_map (path, -1, mode, capacity, access, options, error);
-                       if (file_handle) {
-                               file_handle->handle.name = g_strdup (c_mapName);
-                               g_hash_table_insert (named_regions, file_handle->handle.name, file_handle);
+                       handle = open_file_map (path, -1, mode, capacity, access, options, error);
+                       if (handle) {
+                               handle->name = g_strdup (c_mapName);
+                               g_hash_table_insert (named_regions, handle->name, handle);
                        }
                }
                named_regions_unlock ();
 
                g_free (c_mapName);
-               return file_handle;
+               return handle;
        }
 
        return open_memory_map (mapName, mode, capacity, access, options, error);
 }
 
 void *
-mono_mmap_open_handle (void *handle, MonoString *mapName, gint64 *capacity, int access, int options, int *error)
+mono_mmap_open_handle (void *input_fd, MonoString *mapName, gint64 *capacity, int access, int options, int *error)
 {
-       FileHandle *file_handle;
+       MmapHandle *handle;
        char *c_mapName = mono_string_to_utf8 (mapName);
 
        named_regions_lock ();
-       file_handle = (FileHandle*)g_hash_table_lookup (named_regions, c_mapName);
-       if (file_handle) {
+       handle = (MmapHandle*)g_hash_table_lookup (named_regions, c_mapName);
+       if (handle) {
                *error = FILE_ALREADY_EXISTS;
-               file_handle = NULL;
+               handle = NULL;
        } else {
                //XXX we're exploiting wapi HANDLE == FD equivalence. THIS IS FRAGILE, create a _wapi_handle_to_fd call
-               file_handle = open_file_map (NULL, GPOINTER_TO_INT (handle), FILE_MODE_OPEN, capacity, access, options, error);
-               file_handle->handle.name = g_strdup (c_mapName);
-               g_hash_table_insert (named_regions, file_handle->handle.name, file_handle);
+               handle = open_file_map (NULL, GPOINTER_TO_INT (input_fd), FILE_MODE_OPEN, capacity, access, options, error);
+               handle->name = g_strdup (c_mapName);
+               g_hash_table_insert (named_regions, handle->name, handle);
        }
        named_regions_unlock ();
 
        g_free (c_mapName);
-       return file_handle;
+       return handle;
 }
 
 void
 mono_mmap_close (void *mmap_handle)
 {
-       Handle *handle = mmap_handle;
+       MmapHandle *handle = mmap_handle;
 
        named_regions_lock ();
        --handle->ref_count;
        if (handle->ref_count == 0) {
                if (handle->name)
                        g_hash_table_remove (named_regions, handle->name);
-               
+
                g_free (handle->name);
-               if (handle->kind == MMAP_KIND_MEMORY)
-                       mono_vfree (((MemoryHandle*)handle)->address, ((MemoryHandle*)handle)->length);
-               else
-                       close (((FileHandle*)handle)->fd);
+               close (handle->fd);
                g_free (handle);
        }
        named_regions_unlock ();
@@ -441,12 +450,9 @@ mono_mmap_close (void *mmap_handle)
 void
 mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability)
 {
-       FileHandle *h = mmap_handle;
+       MmapHandle *h = mmap_handle;
        int fd, flags;
 
-       if (h->handle.kind != MMAP_KIND_FILE)
-               return;
-
        fd = h->fd;
        flags = fcntl (fd, F_GETFD, 0);
        if (inheritability)
@@ -459,7 +465,7 @@ mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability)
 void
 mono_mmap_flush (void *mmap_handle)
 {
-       MmapHandle *h = mmap_handle;
+       MmapInstance *h = mmap_handle;
 
        if (h)
                msync (h->address, h->length, MS_SYNC);
@@ -469,44 +475,29 @@ int
 mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address)
 {
        gint64 mmap_offset = 0;
-       Handle *h = handle;
-       MmapHandle res = { 0 };
-       if (h->kind == MMAP_KIND_FILE) {
-               FileHandle *fh = (FileHandle*)h;
-               size_t eff_size = *size;
-               struct stat buf = { 0 };
-               fstat (fh->fd, &buf); //FIXME error handling
-
-               /**
-                 * We use the file size if one of the following conditions is true:
-                 *  -input size is zero
-                 *  -input size is bigger than the file and the file is not a magical zero size file such as /dev/mem.
-                 */
-               if (eff_size == 0 || (eff_size > buf.st_size && !is_special_zero_size_file (&buf)))
-                       eff_size = buf.st_size;
-               *size = eff_size;
-
-               mmap_offset = align_down_to_page_size (offset);
-               eff_size += (offset - mmap_offset);
-               //FIXME translate some interesting errno values
-               res.address = mono_file_map ((size_t)eff_size, acess_to_mmap_flags (access), fh->fd, mmap_offset, &res.free_handle);
-               res.length = eff_size;
-               res.kind = MMAP_KIND_FILE;
-
-       } else {
-               MemoryHandle *mh = (MemoryHandle*)h;
-               size_t eff_size = *size;
-
-               if (!eff_size)
-                       eff_size = *size = mh->length;
-               mmap_offset = (size_t)offset;
-               res.address = (char*)mh->address + offset;
-               res.length = (size_t)*size;
-               res.kind = MMAP_KIND_MEMORY;
-       }
+       MmapHandle *fh = handle;
+       MmapInstance res = { 0 };
+       size_t eff_size = *size;
+       struct stat buf = { 0 };
+       fstat (fh->fd, &buf); //FIXME error handling
+
+       /**
+         * We use the file size if one of the following conditions is true:
+         *  -input size is zero
+         *  -input size is bigger than the file and the file is not a magical zero size file such as /dev/mem.
+         */
+       if (eff_size == 0 || (eff_size > buf.st_size && !is_special_zero_size_file (&buf)))
+               eff_size = buf.st_size;
+       *size = eff_size;
+
+       mmap_offset = align_down_to_page_size (offset);
+       eff_size += (offset - mmap_offset);
+       //FIXME translate some interesting errno values
+       res.address = mono_file_map ((size_t)eff_size, acess_to_mmap_flags (access), fh->fd, mmap_offset, &res.free_handle);
+       res.length = eff_size;
 
        if (res.address) {
-               *mmap_handle = g_memdup (&res, sizeof (MmapHandle));
+               *mmap_handle = g_memdup (&res, sizeof (MmapInstance));
                *base_address = (char*)res.address + (offset - mmap_offset);
                return 0;
        }
@@ -520,10 +511,9 @@ gboolean
 mono_mmap_unmap (void *mmap_handle)
 {
        int res = 0;
-       MmapHandle *h = mmap_handle;
+       MmapInstance *h = mmap_handle;
 
-       if (h->kind == MMAP_KIND_FILE)
-               res = mono_file_unmap (h->address, h->free_handle);
+       res = mono_file_unmap (h->address, h->free_handle);
 
        g_free (h);
        return res == 0;