int mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address) { gint64 mmap_offset = 0; MmapHandle *fh = (MmapHandle *)handle; MmapInstance res = { 0 }; size_t eff_size = *size; struct stat buf = { 0 }; fstat (fh->fd, &buf); //FIXME error handling *mmap_handle = NULL; *base_address = NULL; if (offset > buf.st_size || ((eff_size + offset) > buf.st_size && !is_special_zero_size_file (&buf))) return ACCESS_DENIED; /** * 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 = align_up_to_page_size (buf.st_size) - offset; *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 (MmapInstance)); *base_address = (char*)res.address + (offset - mmap_offset); return 0; } return COULD_NOT_MAP_MEMORY; }
static void* open_memory_map (MonoString *mapName, int mode, gint64 *capacity, int access, int options, int *error) { char *c_mapName; MmapHandle *handle; if (*capacity <= 1) { *error = CAPACITY_MUST_BE_POSITIVE; return NULL; } if (!(mode == FILE_MODE_CREATE_NEW || mode == FILE_MODE_OPEN_OR_CREATE || mode == FILE_MODE_OPEN)) { *error = INVALID_FILE_MODE; return NULL; } c_mapName = mono_string_to_utf8 (mapName); named_regions_lock (); handle = (MmapHandle*)g_hash_table_lookup (named_regions, c_mapName); if (handle) { if (mode == FILE_MODE_CREATE_NEW) { *error = FILE_ALREADY_EXISTS; goto done; } handle->ref_count++; //XXX should we ftruncate if the file is smaller than capacity? } else { int fd; char file_name [sizeof (MONO_ANON_FILE_TEMPLATE) + 1]; int unused G_GNUC_UNUSED; if (mode == FILE_MODE_OPEN) { *error = FILE_NOT_FOUND; goto done; } *capacity = align_up_to_page_size (*capacity); strcpy (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); } done: named_regions_unlock (); g_free (c_mapName); return handle; }
/* XXX implement options */ static void* open_file_map (MonoString *path, int input_fd, int mode, gint64 *capacity, int access, int options, int *error) { struct stat buf; char *c_path = path ? mono_string_to_utf8 (path) : NULL; MmapHandle *handle = NULL; int result, fd; if (path) result = stat (c_path, &buf); else result = fstat (input_fd, &buf); if (mode == FILE_MODE_TRUNCATE || mode == FILE_MODE_APPEND || mode == FILE_MODE_OPEN) { if (result == -1) { //XXX translate errno? *error = FILE_NOT_FOUND; goto done; } } if (mode == FILE_MODE_CREATE_NEW && result == 0) { *error = FILE_ALREADY_EXISTS; goto done; } if (result == 0) { if (*capacity == 0) { /** * Special files such as FIFOs, sockets, and devices can have a size of 0. Specifying a capacity for these * also makes little sense, so don't do the check if th file is one of these. */ if (buf.st_size == 0 && !is_special_zero_size_file (&buf)) { *error = CAPACITY_SMALLER_THAN_FILE_SIZE; goto done; } *capacity = buf.st_size; } else if (*capacity < buf.st_size) { *error = CAPACITY_SMALLER_THAN_FILE_SIZE; goto done; } } else { if (mode == FILE_MODE_CREATE_NEW && *capacity == 0) { *error = CAPACITY_SMALLER_THAN_FILE_SIZE; goto done; } } if (path) //FIXME use io portability? fd = open (c_path, file_mode_to_unix (mode) | access_mode_to_unix (access), DEFAULT_FILEMODE); else fd = dup (input_fd); if (fd == -1) { //XXX translate errno? *error = COULD_NOT_OPEN; goto done; } *capacity = align_up_to_page_size ((size_t)*capacity); if (*capacity > buf.st_size) { int unused G_GNUC_UNUSED = ftruncate (fd, (off_t)*capacity); } handle = g_new0 (MmapHandle, 1); handle->ref_count = 1; handle->capacity = *capacity; handle->fd = fd; done: g_free (c_path); return (void*)handle; }
static void* open_memory_map (const char *c_mapName, int mode, gint64 *capacity, int access, int options, int *ioerror) { MmapHandle *handle; if (*capacity <= 0) { *ioerror = CAPACITY_MUST_BE_POSITIVE; return NULL; } #if SIZEOF_VOID_P == 4 if (*capacity > UINT32_MAX) { *ioerror = CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE; return NULL; } #endif if (!(mode == FILE_MODE_CREATE_NEW || mode == FILE_MODE_OPEN_OR_CREATE || mode == FILE_MODE_OPEN)) { *ioerror = INVALID_FILE_MODE; return NULL; } named_regions_lock (); handle = (MmapHandle*)g_hash_table_lookup (named_regions, c_mapName); if (handle) { if (mode == FILE_MODE_CREATE_NEW) { *ioerror = FILE_ALREADY_EXISTS; goto done; } handle->ref_count++; //XXX should we ftruncate if the file is smaller than capacity? } else { int fd; char *file_name; const char *tmp_dir; int unused G_GNUC_UNUSED, alloc_size; if (mode == FILE_MODE_OPEN) { *ioerror = FILE_NOT_FOUND; goto done; } *capacity = align_up_to_page_size (*capacity); 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 *ioerror = COULD_NOT_MAP_MEMORY; goto done; } file_name = (char *)alloca (alloc_size); strcpy (file_name, tmp_dir); strcat (file_name, MONO_ANON_FILE_TEMPLATE); fd = mkstemp (file_name); if (fd == -1) { *ioerror = 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); } done: named_regions_unlock (); return handle; }