blob: e34a436afb59c84c00eab2da670640461b6e2c11 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <private/primpl.h>
#include <string.h>
#include <prshm.h>
#include <prerr.h>
#include <prmem.h>
#if defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY)
extern PRLogModuleInfo *_pr_shm_lm;
/*
* NSPR-to-NT access right mapping table for file-mapping objects.
*
* The OR of these three access masks must equal FILE_MAP_ALL_ACCESS.
* This is because if a file-mapping object with the specified name
* exists, CreateFileMapping requests full access to the existing
* object.
*/
static DWORD filemapAccessTable[] = {
FILE_MAP_ALL_ACCESS & ~FILE_MAP_WRITE, /* read */
FILE_MAP_ALL_ACCESS & ~FILE_MAP_READ, /* write */
0 /* execute */
};
extern PRSharedMemory * _MD_OpenSharedMemory(
const char *name,
PRSize size,
PRIntn flags,
PRIntn mode
)
{
char ipcname[PR_IPC_NAME_SIZE];
PRStatus rc = PR_SUCCESS;
DWORD dwHi, dwLo;
PRSharedMemory *shm;
DWORD flProtect = ( PAGE_READWRITE );
SECURITY_ATTRIBUTES sa;
LPSECURITY_ATTRIBUTES lpSA = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pACL = NULL;
rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
if ( PR_FAILURE == rc )
{
PR_SetError(PR_UNKNOWN_ERROR, 0 );
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: name is invalid"));
return(NULL);
}
shm = PR_NEWZAP( PRSharedMemory );
if ( NULL == shm )
{
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory"));
return(NULL);
}
shm->ipcname = PR_MALLOC( (PRUint32) (strlen( ipcname ) + 1) );
if ( NULL == shm->ipcname )
{
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory"));
PR_DELETE(shm);
return(NULL);
}
/* copy args to struct */
strcpy( shm->ipcname, ipcname );
shm->size = size;
shm->mode = mode;
shm->flags = flags;
shm->ident = _PR_SHM_IDENT;
if (flags & PR_SHM_CREATE ) {
dwHi = (DWORD) (((PRUint64) shm->size >> 32) & 0xffffffff);
dwLo = (DWORD) (shm->size & 0xffffffff);
if (_PR_NT_MakeSecurityDescriptorACL(mode, filemapAccessTable,
&pSD, &pACL) == PR_SUCCESS) {
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
lpSA = &sa;
}
#ifdef WINCE
{
/*
* This is assuming that the name will never be larger than
* MAX_PATH. Should we dynamically allocate?
*/
PRUnichar wideIpcName[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, shm->ipcname, -1,
wideIpcName, MAX_PATH);
shm->handle = CreateFileMappingW(
(HANDLE)-1 ,
lpSA,
flProtect,
dwHi,
dwLo,
wideIpcName);
}
#else
shm->handle = CreateFileMappingA(
(HANDLE)-1 ,
lpSA,
flProtect,
dwHi,
dwLo,
shm->ipcname);
#endif
if (lpSA != NULL) {
_PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
}
if ( NULL == shm->handle ) {
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
( "PR_OpenSharedMemory: CreateFileMapping() failed: %s",
shm->ipcname ));
_PR_MD_MAP_DEFAULT_ERROR( GetLastError());
PR_FREEIF( shm->ipcname )
PR_DELETE( shm );
return(NULL);
} else {
if (( flags & PR_SHM_EXCL) && ( GetLastError() == ERROR_ALREADY_EXISTS )) {
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
( "PR_OpenSharedMemory: Request exclusive & already exists",
shm->ipcname ));
PR_SetError( PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS );
CloseHandle( shm->handle );
PR_FREEIF( shm->ipcname )
PR_DELETE( shm );
return(NULL);
} else {
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
( "PR_OpenSharedMemory: CreateFileMapping() success: %s, handle: %d",
shm->ipcname, shm->handle ));
return(shm);
}
}
} else {
#ifdef WINCE
PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
shm->handle = NULL; /* OpenFileMapping not supported */
#else
shm->handle = OpenFileMapping( FILE_MAP_WRITE, TRUE, shm->ipcname );
#endif
if ( NULL == shm->handle ) {
_PR_MD_MAP_DEFAULT_ERROR( GetLastError());
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
( "PR_OpenSharedMemory: OpenFileMapping() failed: %s, error: %d",
shm->ipcname, PR_GetOSError()));
PR_FREEIF( shm->ipcname );
PR_DELETE( shm );
return(NULL);
} else {
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
( "PR_OpenSharedMemory: OpenFileMapping() success: %s, handle: %d",
shm->ipcname, shm->handle ));
return(shm);
}
}
/* returns from separate paths */
}
extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
{
PRUint32 access = FILE_MAP_WRITE;
void *addr;
PR_ASSERT( shm->ident == _PR_SHM_IDENT );
if ( PR_SHM_READONLY & flags )
access = FILE_MAP_READ;
addr = MapViewOfFile( shm->handle,
access,
0, 0,
shm->size );
if ( NULL == addr ) {
_PR_MD_MAP_DEFAULT_ERROR( GetLastError());
PR_LOG( _pr_shm_lm, PR_LOG_ERROR,
("_MD_AttachSharedMemory: MapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
}
return( addr );
} /* end _MD_ATTACH_SHARED_MEMORY() */
extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
{
PRStatus rc = PR_SUCCESS;
BOOL wrc;
PR_ASSERT( shm->ident == _PR_SHM_IDENT );
wrc = UnmapViewOfFile( addr );
if ( FALSE == wrc )
{
_PR_MD_MAP_DEFAULT_ERROR( GetLastError());
PR_LOG( _pr_shm_lm, PR_LOG_ERROR,
("_MD_DetachSharedMemory: UnmapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
rc = PR_FAILURE;
}
return( rc );
}
extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
{
PRStatus rc = PR_SUCCESS;
BOOL wrc;
PR_ASSERT( shm->ident == _PR_SHM_IDENT );
wrc = CloseHandle( shm->handle );
if ( FALSE == wrc )
{
_PR_MD_MAP_DEFAULT_ERROR( GetLastError());
PR_LOG( _pr_shm_lm, PR_LOG_ERROR,
("_MD_CloseSharedMemory: CloseHandle() failed. OSerror: %d", PR_GetOSError()));
rc = PR_FAILURE;
}
PR_FREEIF( shm->ipcname );
PR_DELETE( shm );
return( rc );
} /* end _MD_CLOSE_SHARED_MEMORY() */
extern PRStatus _MD_DeleteSharedMemory( const char *name )
{
return( PR_SUCCESS );
}
/*
** Windows implementation of anonymous memory (file) map
*/
extern PRLogModuleInfo *_pr_shma_lm;
extern PRFileMap* _md_OpenAnonFileMap(
const char *dirName,
PRSize size,
PRFileMapProtect prot
)
{
PRFileMap *fm;
HANDLE hFileMap;
fm = PR_CreateFileMap( (PRFileDesc*)-1, size, prot );
if ( NULL == fm ) {
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
("_md_OpenAnonFileMap(): PR_CreateFileMap(): failed"));
goto Finished;
}
/*
** Make fm->md.hFileMap inheritable. We can't use
** GetHandleInformation and SetHandleInformation
** because these two functions fail with
** ERROR_CALL_NOT_IMPLEMENTED on Win95.
*/
if (DuplicateHandle(GetCurrentProcess(), fm->md.hFileMap,
GetCurrentProcess(), &hFileMap,
0, TRUE /* inheritable */,
DUPLICATE_SAME_ACCESS) == FALSE) {
PR_SetError( PR_UNKNOWN_ERROR, GetLastError() );
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
("_md_OpenAnonFileMap(): DuplicateHandle(): failed"));
PR_CloseFileMap( fm );
fm = NULL;
goto Finished;
}
CloseHandle(fm->md.hFileMap);
fm->md.hFileMap = hFileMap;
Finished:
return(fm);
} /* end md_OpenAnonFileMap() */
/*
** _md_ExportFileMapAsString()
**
*/
extern PRStatus _md_ExportFileMapAsString(
PRFileMap *fm,
PRSize bufSize,
char *buf
)
{
PRIntn written;
written = PR_snprintf( buf, (PRUint32) bufSize, "%d:%" PR_PRIdOSFD ":%ld",
(PRIntn)fm->prot, (PROsfd)fm->md.hFileMap, (PRInt32)fm->md.dwAccess );
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
("_md_ExportFileMapAsString(): prot: %x, hFileMap: %x, dwAccess: %x",
fm->prot, fm->md.hFileMap, fm->md.dwAccess ));
return((written == -1)? PR_FAILURE : PR_SUCCESS);
} /* end _md_ExportFileMapAsString() */
/*
** _md_ImportFileMapFromString()
**
*/
extern PRFileMap * _md_ImportFileMapFromString(
const char *fmstring
)
{
PRIntn prot;
PROsfd hFileMap;
PRInt32 dwAccess;
PRFileMap *fm = NULL;
PR_sscanf( fmstring, "%d:%" PR_SCNdOSFD ":%ld",
&prot, &hFileMap, &dwAccess );
fm = PR_NEWZAP(PRFileMap);
if ( NULL == fm ) {
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
("_md_ImportFileMapFromString(): PR_NEWZAP(): Failed"));
return(fm);
}
fm->prot = (PRFileMapProtect)prot;
fm->md.hFileMap = (HANDLE)hFileMap;
fm->md.dwAccess = (DWORD)dwAccess;
fm->fd = (PRFileDesc*)-1;
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
("_md_ImportFileMapFromString(): fm: %p, prot: %d, hFileMap: %8.8x, dwAccess: %8.8x, fd: %x",
fm, prot, fm->md.hFileMap, fm->md.dwAccess, fm->fd));
return(fm);
} /* end _md_ImportFileMapFromString() */
#else
Error! Why is PR_HAVE_WIN32_NAMED_SHARED_MEMORY not defined?
#endif /* PR_HAVE_WIN32_NAMED_SHARED_MEMORY */
/* --- end w32shm.c --- */