|  | /* | 
|  | * Server-side file mapping management | 
|  | * | 
|  | * Copyright (C) 1999 Alexandre Julliard | 
|  | */ | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | #include "config.h" | 
|  | #include "winerror.h" | 
|  | #include "winnt.h" | 
|  | #include "winbase.h" | 
|  |  | 
|  | #include "handle.h" | 
|  | #include "thread.h" | 
|  | #include "request.h" | 
|  |  | 
|  | struct mapping | 
|  | { | 
|  | struct object  obj;             /* object header */ | 
|  | int            size_high;       /* mapping size */ | 
|  | int            size_low;        /* mapping size */ | 
|  | int            protect;         /* protection flags */ | 
|  | struct file   *file;            /* file mapped */ | 
|  | }; | 
|  |  | 
|  | static void mapping_dump( struct object *obj, int verbose ); | 
|  | static void mapping_destroy( struct object *obj ); | 
|  |  | 
|  | static const struct object_ops mapping_ops = | 
|  | { | 
|  | sizeof(struct mapping), | 
|  | mapping_dump, | 
|  | no_add_queue, | 
|  | NULL,  /* should never get called */ | 
|  | NULL,  /* should never get called */ | 
|  | NULL,  /* should never get called */ | 
|  | no_read_fd, | 
|  | no_write_fd, | 
|  | no_flush, | 
|  | no_get_file_info, | 
|  | 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) | 
|  |  | 
|  |  | 
|  | static struct object *create_mapping( int size_high, int size_low, int protect, | 
|  | int handle, const char *name, size_t len ) | 
|  | { | 
|  | struct mapping *mapping; | 
|  | int access = 0; | 
|  |  | 
|  | if (!page_mask) init_page_size(); | 
|  |  | 
|  | if (!(mapping = create_named_object( &mapping_ops, name, len ))) | 
|  | return NULL; | 
|  | 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; | 
|  |  | 
|  | if (handle != -1) | 
|  | { | 
|  | if (!(mapping->file = get_file_obj( current->process, handle, access ))) goto error; | 
|  | if (!size_high && !size_low) | 
|  | { | 
|  | struct get_file_info_request req; | 
|  | struct object *obj = (struct object *)mapping->file; | 
|  | obj->ops->get_file_info( obj, &req ); | 
|  | size_high = req.size_high; | 
|  | size_low  = ROUND_SIZE( 0, req.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  = ROUND_SIZE( 0, size_low ); | 
|  | mapping->protect   = protect; | 
|  | return &mapping->obj; | 
|  |  | 
|  | error: | 
|  | release_object( mapping ); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static void mapping_dump( struct object *obj, int verbose ) | 
|  | { | 
|  | struct mapping *mapping = (struct mapping *)obj; | 
|  | assert( obj->ops == &mapping_ops ); | 
|  | fprintf( stderr, "Mapping size=%08x%08x prot=%08x file=%p name='%s'\n", | 
|  | mapping->size_high, mapping->size_low, mapping->protect, | 
|  | mapping->file, get_object_name( &mapping->obj ) ); | 
|  | } | 
|  |  | 
|  | static void mapping_destroy( struct object *obj ) | 
|  | { | 
|  | struct mapping *mapping = (struct mapping *)obj; | 
|  | assert( obj->ops == &mapping_ops ); | 
|  | if (mapping->file) release_object( mapping->file ); | 
|  | } | 
|  |  | 
|  | /* create a file mapping */ | 
|  | DECL_HANDLER(create_mapping) | 
|  | { | 
|  | size_t len = get_req_strlen( req->name ); | 
|  | struct object *obj; | 
|  |  | 
|  | req->handle = -1; | 
|  | if ((obj = create_mapping( req->size_high, req->size_low, | 
|  | req->protect, req->file_handle, req->name, len ))) | 
|  | { | 
|  | int access = FILE_MAP_ALL_ACCESS; | 
|  | if (!(req->protect & VPROT_WRITE)) access &= ~FILE_MAP_WRITE; | 
|  | req->handle = alloc_handle( current->process, obj, access, req->inherit ); | 
|  | release_object( obj ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* open a handle to a mapping */ | 
|  | DECL_HANDLER(open_mapping) | 
|  | { | 
|  | size_t len = get_req_strlen( req->name ); | 
|  | req->handle = open_object( req->name, len, &mapping_ops, req->access, req->inherit ); | 
|  | } | 
|  |  | 
|  | /* get a mapping information */ | 
|  | DECL_HANDLER(get_mapping_info) | 
|  | { | 
|  | struct mapping *mapping; | 
|  |  | 
|  | if ((mapping = (struct mapping *)get_handle_obj( current->process, req->handle, | 
|  | 0, &mapping_ops ))) | 
|  | { | 
|  | req->size_high = mapping->size_high; | 
|  | req->size_low  = mapping->size_low; | 
|  | req->protect   = mapping->protect; | 
|  | if (mapping->file) set_reply_fd( current, file_get_mmap_fd( mapping->file ) ); | 
|  | release_object( mapping ); | 
|  | } | 
|  | } | 
|  |  |