1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include <private/primpl.h>
7 #include <string.h>
8 #include <prshm.h>
9 #include <prerr.h>
10 #include <prmem.h>
11 
12 #if defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY)
13 
14 extern PRLogModuleInfo *_pr_shm_lm;
15 
16 /*
17  * NSPR-to-NT access right mapping table for file-mapping objects.
18  *
19  * The OR of these three access masks must equal FILE_MAP_ALL_ACCESS.
20  * This is because if a file-mapping object with the specified name
21  * exists, CreateFileMapping requests full access to the existing
22  * object.
23  */
24 static DWORD filemapAccessTable[] = {
25     FILE_MAP_ALL_ACCESS & ~FILE_MAP_WRITE, /* read */
26     FILE_MAP_ALL_ACCESS & ~FILE_MAP_READ, /* write */
27     0  /* execute */
28 };
29 
_MD_OpenSharedMemory(const char * name,PRSize size,PRIntn flags,PRIntn mode)30 extern PRSharedMemory * _MD_OpenSharedMemory(
31     const char *name,
32     PRSize      size,
33     PRIntn      flags,
34     PRIntn      mode
35 )
36 {
37     char        ipcname[PR_IPC_NAME_SIZE];
38     PRStatus    rc = PR_SUCCESS;
39     DWORD dwHi, dwLo;
40     PRSharedMemory *shm;
41     DWORD flProtect = ( PAGE_READWRITE );
42     SECURITY_ATTRIBUTES sa;
43     LPSECURITY_ATTRIBUTES lpSA = NULL;
44     PSECURITY_DESCRIPTOR pSD = NULL;
45     PACL pACL = NULL;
46 
47     rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
48     if ( PR_FAILURE == rc )
49     {
50         PR_SetError(PR_UNKNOWN_ERROR, 0 );
51         PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: name is invalid"));
52         return(NULL);
53     }
54 
55     shm = PR_NEWZAP( PRSharedMemory );
56     if ( NULL == shm )
57     {
58         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
59         PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory"));
60         return(NULL);
61     }
62 
63     shm->ipcname = PR_MALLOC( (PRUint32) (strlen( ipcname ) + 1) );
64     if ( NULL == shm->ipcname )
65     {
66         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
67         PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory"));
68         PR_DELETE(shm);
69         return(NULL);
70     }
71 
72     /* copy args to struct */
73     strcpy( shm->ipcname, ipcname );
74     shm->size = size;
75     shm->mode = mode;
76     shm->flags = flags;
77     shm->ident = _PR_SHM_IDENT;
78 
79     if (flags & PR_SHM_CREATE ) {
80         dwHi = (DWORD) (((PRUint64) shm->size >> 32) & 0xffffffff);
81         dwLo = (DWORD) (shm->size & 0xffffffff);
82 
83         if (_PR_NT_MakeSecurityDescriptorACL(mode, filemapAccessTable,
84                                              &pSD, &pACL) == PR_SUCCESS) {
85             sa.nLength = sizeof(sa);
86             sa.lpSecurityDescriptor = pSD;
87             sa.bInheritHandle = FALSE;
88             lpSA = &sa;
89         }
90 #ifdef WINCE
91         {
92             /*
93              * This is assuming that the name will never be larger than
94              * MAX_PATH.  Should we dynamically allocate?
95              */
96             PRUnichar wideIpcName[MAX_PATH];
97             MultiByteToWideChar(CP_ACP, 0, shm->ipcname, -1,
98                                 wideIpcName, MAX_PATH);
99             shm->handle = CreateFileMappingW(
100                               (HANDLE)-1,
101                               lpSA,
102                               flProtect,
103                               dwHi,
104                               dwLo,
105                               wideIpcName);
106         }
107 #else
108         shm->handle = CreateFileMappingA(
109                           (HANDLE)-1,
110                           lpSA,
111                           flProtect,
112                           dwHi,
113                           dwLo,
114                           shm->ipcname);
115 #endif
116         if (lpSA != NULL) {
117             _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
118         }
119 
120         if ( NULL == shm->handle ) {
121             PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
122                    ( "PR_OpenSharedMemory: CreateFileMapping() failed: %s",
123                      shm->ipcname ));
124             _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
125             PR_FREEIF( shm->ipcname )
126             PR_DELETE( shm );
127             return(NULL);
128         } else {
129             if (( flags & PR_SHM_EXCL) && ( GetLastError() == ERROR_ALREADY_EXISTS ))  {
130                 PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
131                        ( "PR_OpenSharedMemory: Request exclusive & already exists",
132                          shm->ipcname ));
133                 PR_SetError( PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS );
134                 CloseHandle( shm->handle );
135                 PR_FREEIF( shm->ipcname )
136                 PR_DELETE( shm );
137                 return(NULL);
138             } else {
139                 PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
140                        ( "PR_OpenSharedMemory: CreateFileMapping() success: %s, handle: %d",
141                          shm->ipcname, shm->handle ));
142                 return(shm);
143             }
144         }
145     } else {
146 #ifdef WINCE
147         PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
148         shm->handle = NULL;  /* OpenFileMapping not supported */
149 #else
150         shm->handle = OpenFileMapping( FILE_MAP_WRITE, TRUE, shm->ipcname );
151 #endif
152         if ( NULL == shm->handle ) {
153             _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
154             PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
155                    ( "PR_OpenSharedMemory: OpenFileMapping() failed: %s, error: %d",
156                      shm->ipcname, PR_GetOSError()));
157             PR_FREEIF( shm->ipcname );
158             PR_DELETE( shm );
159             return(NULL);
160         } else {
161             PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
162                    ( "PR_OpenSharedMemory: OpenFileMapping() success: %s, handle: %d",
163                      shm->ipcname, shm->handle ));
164             return(shm);
165         }
166     }
167     /* returns from separate paths */
168 }
169 
_MD_AttachSharedMemory(PRSharedMemory * shm,PRIntn flags)170 extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
171 {
172     PRUint32    access = FILE_MAP_WRITE;
173     void        *addr;
174 
175     PR_ASSERT( shm->ident == _PR_SHM_IDENT );
176 
177     if ( PR_SHM_READONLY & flags ) {
178         access = FILE_MAP_READ;
179     }
180 
181     addr = MapViewOfFile( shm->handle,
182                           access,
183                           0, 0,
184                           shm->size );
185 
186     if ( NULL == addr ) {
187         _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
188         PR_LOG( _pr_shm_lm, PR_LOG_ERROR,
189                 ("_MD_AttachSharedMemory: MapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
190     }
191 
192     return( addr );
193 } /* end _MD_ATTACH_SHARED_MEMORY() */
194 
195 
_MD_DetachSharedMemory(PRSharedMemory * shm,void * addr)196 extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
197 {
198     PRStatus rc = PR_SUCCESS;
199     BOOL        wrc;
200 
201     PR_ASSERT( shm->ident == _PR_SHM_IDENT );
202 
203     wrc = UnmapViewOfFile( addr );
204     if ( FALSE == wrc )
205     {
206         _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
207         PR_LOG( _pr_shm_lm, PR_LOG_ERROR,
208                 ("_MD_DetachSharedMemory: UnmapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
209         rc = PR_FAILURE;
210     }
211 
212     return( rc );
213 }
214 
215 
_MD_CloseSharedMemory(PRSharedMemory * shm)216 extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
217 {
218     PRStatus rc = PR_SUCCESS;
219     BOOL wrc;
220 
221     PR_ASSERT( shm->ident == _PR_SHM_IDENT );
222 
223     wrc = CloseHandle( shm->handle );
224     if ( FALSE == wrc )
225     {
226         _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
227         PR_LOG( _pr_shm_lm, PR_LOG_ERROR,
228                 ("_MD_CloseSharedMemory: CloseHandle() failed. OSerror: %d", PR_GetOSError()));
229         rc = PR_FAILURE;
230     }
231     PR_FREEIF( shm->ipcname );
232     PR_DELETE( shm );
233 
234     return( rc );
235 } /* end _MD_CLOSE_SHARED_MEMORY() */
236 
_MD_DeleteSharedMemory(const char * name)237 extern PRStatus _MD_DeleteSharedMemory( const char *name )
238 {
239     return( PR_SUCCESS );
240 }
241 
242 
243 /*
244 ** Windows implementation of anonymous memory (file) map
245 */
246 extern PRLogModuleInfo *_pr_shma_lm;
247 
_md_OpenAnonFileMap(const char * dirName,PRSize size,PRFileMapProtect prot)248 extern PRFileMap* _md_OpenAnonFileMap(
249     const char *dirName,
250     PRSize      size,
251     PRFileMapProtect prot
252 )
253 {
254     PRFileMap   *fm;
255     HANDLE      hFileMap;
256 
257     fm = PR_CreateFileMap( (PRFileDesc*)-1, size, prot );
258     if ( NULL == fm )  {
259         PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
260                 ("_md_OpenAnonFileMap(): PR_CreateFileMap(): failed"));
261         goto Finished;
262     }
263 
264     /*
265     ** Make fm->md.hFileMap inheritable. We can't use
266     ** GetHandleInformation and SetHandleInformation
267     ** because these two functions fail with
268     ** ERROR_CALL_NOT_IMPLEMENTED on Win95.
269     */
270     if (DuplicateHandle(GetCurrentProcess(), fm->md.hFileMap,
271                         GetCurrentProcess(), &hFileMap,
272                         0, TRUE /* inheritable */,
273                         DUPLICATE_SAME_ACCESS) == FALSE) {
274         PR_SetError( PR_UNKNOWN_ERROR, GetLastError() );
275         PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
276                 ("_md_OpenAnonFileMap(): DuplicateHandle(): failed"));
277         PR_CloseFileMap( fm );
278         fm = NULL;
279         goto Finished;
280     }
281     CloseHandle(fm->md.hFileMap);
282     fm->md.hFileMap = hFileMap;
283 
284 Finished:
285     return(fm);
286 } /* end md_OpenAnonFileMap() */
287 
288 /*
289 ** _md_ExportFileMapAsString()
290 **
291 */
_md_ExportFileMapAsString(PRFileMap * fm,PRSize bufSize,char * buf)292 extern PRStatus _md_ExportFileMapAsString(
293     PRFileMap *fm,
294     PRSize    bufSize,
295     char      *buf
296 )
297 {
298     PRIntn  written;
299 
300     written = PR_snprintf( buf, (PRUint32) bufSize, "%d:%" PR_PRIdOSFD ":%ld",
301                            (PRIntn)fm->prot, (PROsfd)fm->md.hFileMap, (PRInt32)fm->md.dwAccess );
302 
303     PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
304             ("_md_ExportFileMapAsString(): prot: %x, hFileMap: %x, dwAccess: %x",
305              fm->prot, fm->md.hFileMap, fm->md.dwAccess ));
306 
307     return((written == -1)? PR_FAILURE : PR_SUCCESS);
308 } /* end _md_ExportFileMapAsString() */
309 
310 
311 /*
312 ** _md_ImportFileMapFromString()
313 **
314 */
_md_ImportFileMapFromString(const char * fmstring)315 extern PRFileMap * _md_ImportFileMapFromString(
316     const char *fmstring
317 )
318 {
319     PRIntn  prot;
320     PROsfd hFileMap;
321     PRInt32 dwAccess;
322     PRFileMap *fm = NULL;
323 
324     PR_sscanf( fmstring, "%d:%" PR_SCNdOSFD ":%ld",
325                &prot, &hFileMap, &dwAccess );
326 
327     fm = PR_NEWZAP(PRFileMap);
328     if ( NULL == fm ) {
329         PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
330                 ("_md_ImportFileMapFromString(): PR_NEWZAP(): Failed"));
331         return(fm);
332     }
333 
334     fm->prot = (PRFileMapProtect)prot;
335     fm->md.hFileMap = (HANDLE)hFileMap;
336     fm->md.dwAccess = (DWORD)dwAccess;
337     fm->fd = (PRFileDesc*)-1;
338 
339     PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
340             ("_md_ImportFileMapFromString(): fm: %p, prot: %d, hFileMap: %8.8x, dwAccess: %8.8x, fd: %x",
341              fm, prot, fm->md.hFileMap, fm->md.dwAccess, fm->fd));
342     return(fm);
343 } /* end _md_ImportFileMapFromString() */
344 
345 #else
346 Error! Why is PR_HAVE_WIN32_NAMED_SHARED_MEMORY not defined?
347 #endif /* PR_HAVE_WIN32_NAMED_SHARED_MEMORY */
348 /* --- end w32shm.c --- */
349