diff --git a/include/server/object.h b/include/server/object.h index 7cca59633f..e6dff4b37b 100644 --- a/include/server/object.h +++ b/include/server/object.h @@ -153,6 +153,8 @@ extern struct file *get_file_obj( struct process *process, int handle, extern int file_get_mmap_fd( struct file *file ); extern int set_file_pointer( int handle, int *low, int *high, int whence ); extern int truncate_file( int handle ); +extern int grow_file( struct file *file, int size_high, int size_low ); +extern struct file *create_temp_file( int access ); extern int set_file_time( int handle, time_t access_time, time_t write_time ); extern int file_lock( struct file *file, int offset_high, int offset_low, int count_high, int count_low ); diff --git a/memory/virtual.c b/memory/virtual.c index dd6fe31629..0a9e6b2f1c 100644 --- a/memory/virtual.c +++ b/memory/virtual.c @@ -1109,37 +1109,8 @@ HANDLE WINAPI CreateFileMappingA( /* Compute the size and extend the file if necessary */ - if (hFile == INVALID_HANDLE_VALUE) - { - if (!size_high && !size_low) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - if (name) - { - CHAR buf[260]; - - GetTempPathA(260,buf); - GetTempFileNameA(buf,"wine",0,buf); - hFile = CreateFileA( - buf, - GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_WRITE,/* so we can reuse the tmpfn */ - NULL, - OPEN_ALWAYS, - 0, - 0 - ); - /* FIXME: bad hack to avoid lots of leftover tempfiles */ - DeleteFileA(buf); - if (hFile == INVALID_HANDLE_VALUE) - FIXME(virtual,"could not create temp. file for anon shared mapping: reason was 0x%08lx\n",GetLastError()); - } - } if (hFile != INVALID_HANDLE_VALUE) /* We have a file */ { - BY_HANDLE_FILE_INFORMATION info; DWORD access = GENERIC_READ; if (((protect & 0xff) == PAGE_READWRITE) || @@ -1150,21 +1121,6 @@ HANDLE WINAPI CreateFileMappingA( if ((req.handle = HANDLE_GetServerHandle( PROCESS_Current(), hFile, K32OBJ_FILE, access )) == -1) goto error; - if (!GetFileInformationByHandle( hFile, &info )) goto error; - if (!size_high && !size_low) - { - size_high = info.nFileSizeHigh; - size_low = info.nFileSizeLow; - } - else if ((size_high > info.nFileSizeHigh) || - ((size_high == info.nFileSizeHigh) && - (size_low > info.nFileSizeLow))) - { - /* We have to grow the file */ - if (SetFilePointer( hFile, size_low, &size_high, - FILE_BEGIN ) == 0xffffffff) goto error; - if (!SetEndOfFile( hFile )) goto error; - } } else req.handle = -1; @@ -1173,6 +1129,7 @@ HANDLE WINAPI CreateFileMappingA( req.size_high = size_high; req.size_low = ROUND_SIZE( 0, size_low ); req.protect = vprot; + req.inherit = inherit; CLIENT_SendRequest( REQ_CREATE_MAPPING, -1, 2, &req, sizeof(req), name, name ? strlen(name) + 1 : 0 ); diff --git a/server/file.c b/server/file.c index e2d1c37198..df7af683d6 100644 --- a/server/file.c +++ b/server/file.c @@ -199,6 +199,45 @@ struct object *create_file( int fd, const char *name, unsigned int access, return &file->obj; } +/* Create a temp file for anonymous mappings */ +struct file *create_temp_file( int access ) +{ + struct file *file; + char *name; + int fd; + + do + { + if (!(name = tmpnam(NULL))) + { + SET_ERROR( ERROR_TOO_MANY_OPEN_FILES ); + return NULL; + } + fd = open( name, O_CREAT | O_EXCL | O_RDWR, 0600 ); + } while ((fd == -1) && (errno == EEXIST)); + if (fd == -1) + { + file_set_error(); + return NULL; + } + unlink( name ); + + if (!(file = mem_alloc( sizeof(*file) ))) + { + close( fd ); + return NULL; + } + init_object( &file->obj, &file_ops, NULL ); + file->name = NULL; + file->next = NULL; + file->fd = fd; + file->access = access; + file->flags = 0; + file->sharing = 0; + CLEAR_ERROR(); + return file; +} + static void file_dump( struct object *obj, int verbose ) { struct file *file = (struct file *)obj; @@ -406,6 +445,27 @@ int truncate_file( int handle ) } +/* try to grow the file to the specified size */ +int grow_file( struct file *file, int size_high, int size_low ) +{ + struct stat st; + + if (size_high) + { + SET_ERROR( ERROR_INVALID_PARAMETER ); + return 0; + } + if (fstat( file->fd, &st ) == -1) + { + file_set_error(); + return 0; + } + if (st.st_size >= size_low) return 1; /* already large enough */ + if (ftruncate( file->fd, size_low ) != -1) return 1; + file_set_error(); + return 0; +} + int set_file_time( int handle, time_t access_time, time_t write_time ) { struct file *file; diff --git a/server/mapping.c b/server/mapping.c index b6f4b688b7..acacbb6431 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -9,6 +9,7 @@ #include #include +#include "config.h" #include "winerror.h" #include "winnt.h" #include "server/process.h" @@ -40,10 +41,51 @@ static const struct object_ops mapping_ops = mapping_destroy }; +#ifdef __i386__ + +/* These are always the same on an i386, and it will be faster this way */ +# define page_mask 0xfff +# define page_shift 12 +# define init_page_size() /* nothing */ + +#else /* __i386__ */ + +static int page_shift, page_mask; + +static void init_page_size(void) +{ + int page_size; +# ifdef HAVE_GETPAGESIZE + page_size = getpagesize(); +# else +# ifdef __svr4__ + page_size = sysconf(_SC_PAGESIZE); +# else +# error Cannot get the page size on this platform +# endif +# endif + page_mask = page_size - 1; + /* Make sure we have a power of 2 */ + assert( !(page_size & page_mask) ); + page_shift = 0; + while ((1 << page_shift) != page_size) page_shift++; +} +#endif /* __i386__ */ + +#define ROUND_ADDR(addr) \ + ((int)(addr) & ~page_mask) + +#define ROUND_SIZE(addr,size) \ + (((int)(size) + ((int)(addr) & page_mask) + page_mask) & ~page_mask) + + struct object *create_mapping( int size_high, int size_low, int protect, int handle, const char *name ) { struct mapping *mapping; + int access = 0; + + if (!page_mask) init_page_size(); if (!(mapping = (struct mapping *)create_named_object( name, &mapping_ops, sizeof(*mapping) ))) @@ -51,22 +93,42 @@ struct object *create_mapping( int size_high, int size_low, int protect, if (GET_ERROR() == ERROR_ALREADY_EXISTS) return &mapping->obj; /* Nothing else to do */ + if (protect & VPROT_READ) access |= GENERIC_READ; + if (protect & VPROT_WRITE) access |= GENERIC_WRITE; + + size_low = ROUND_SIZE( 0, size_low ); + if (handle != -1) + { + if (!(mapping->file = get_file_obj( current->process, handle, access ))) goto error; + if (!size_high && !size_low) + { + struct get_file_info_reply reply; + struct object *obj = (struct object *)mapping->file; + obj->ops->get_file_info( obj, &reply ); + size_high = reply.size_high; + size_low = ROUND_SIZE( 0, reply.size_low ); + } + else if (!grow_file( mapping->file, size_high, size_low )) goto error; + } + else /* Anonymous mapping (no associated file) */ + { + if (!size_high && !size_low) + { + SET_ERROR( ERROR_INVALID_PARAMETER ); + mapping->file = NULL; + goto error; + } + if (!(mapping->file = create_temp_file( access ))) goto error; + if (!grow_file( mapping->file, size_high, size_low )) goto error; + } mapping->size_high = size_high; mapping->size_low = size_low; mapping->protect = protect; - if (handle != -1) - { - int access = 0; - if (protect & VPROT_READ) access |= GENERIC_READ; - if (protect & VPROT_WRITE) access |= GENERIC_WRITE; - if (!(mapping->file = get_file_obj( current->process, handle, access ))) - { - release_object( mapping ); - return NULL; - } - } - else mapping->file = NULL; return &mapping->obj; + + error: + release_object( mapping ); + return NULL; } int open_mapping( unsigned int access, int inherit, const char *name )