1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/md/os2/os2misc.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,619 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * os2misc.c 1.11 + * 1.12 + */ 1.13 + 1.14 +#ifdef MOZ_OS2_HIGH_MEMORY 1.15 +/* os2safe.h has to be included before os2.h, needed for high mem */ 1.16 +#include <os2safe.h> 1.17 +#endif 1.18 + 1.19 +#include <string.h> 1.20 +#include "primpl.h" 1.21 + 1.22 +extern int _CRT_init(void); 1.23 +extern void _CRT_term(void); 1.24 +extern void __ctordtorInit(int flag); 1.25 +extern void __ctordtorTerm(int flag); 1.26 + 1.27 +char * 1.28 +_PR_MD_GET_ENV(const char *name) 1.29 +{ 1.30 + return getenv(name); 1.31 +} 1.32 + 1.33 +PRIntn 1.34 +_PR_MD_PUT_ENV(const char *name) 1.35 +{ 1.36 + return putenv(name); 1.37 +} 1.38 + 1.39 + 1.40 +/* 1.41 + ************************************************************************** 1.42 + ************************************************************************** 1.43 + ** 1.44 + ** Date and time routines 1.45 + ** 1.46 + ************************************************************************** 1.47 + ************************************************************************** 1.48 + */ 1.49 + 1.50 +#include <sys/timeb.h> 1.51 +/* 1.52 + *----------------------------------------------------------------------- 1.53 + * 1.54 + * PR_Now -- 1.55 + * 1.56 + * Returns the current time in microseconds since the epoch. 1.57 + * The epoch is midnight January 1, 1970 GMT. 1.58 + * The implementation is machine dependent. This is the 1.59 + * implementation for OS/2. 1.60 + * Cf. time_t time(time_t *tp) 1.61 + * 1.62 + *----------------------------------------------------------------------- 1.63 + */ 1.64 + 1.65 +PR_IMPLEMENT(PRTime) 1.66 +PR_Now(void) 1.67 +{ 1.68 + PRInt64 s, ms, ms2us, s2us; 1.69 + struct timeb b; 1.70 + 1.71 + ftime(&b); 1.72 + LL_I2L(ms2us, PR_USEC_PER_MSEC); 1.73 + LL_I2L(s2us, PR_USEC_PER_SEC); 1.74 + LL_I2L(s, b.time); 1.75 + LL_I2L(ms, b.millitm); 1.76 + LL_MUL(ms, ms, ms2us); 1.77 + LL_MUL(s, s, s2us); 1.78 + LL_ADD(s, s, ms); 1.79 + return s; 1.80 +} 1.81 + 1.82 + 1.83 +/* 1.84 + *********************************************************************** 1.85 + *********************************************************************** 1.86 + * 1.87 + * Process creation routines 1.88 + * 1.89 + *********************************************************************** 1.90 + *********************************************************************** 1.91 + */ 1.92 + 1.93 +/* 1.94 + * Assemble the command line by concatenating the argv array. 1.95 + * Special characters intentionally do not get escaped, and it is 1.96 + * expected that the caller wraps arguments in quotes if needed 1.97 + * (e.g. for filename with spaces). 1.98 + * 1.99 + * On success, this function returns 0 and the resulting command 1.100 + * line is returned in *cmdLine. On failure, it returns -1. 1.101 + */ 1.102 +static int assembleCmdLine(char *const *argv, char **cmdLine) 1.103 +{ 1.104 + char *const *arg; 1.105 + int cmdLineSize; 1.106 + 1.107 + /* 1.108 + * Find out how large the command line buffer should be. 1.109 + */ 1.110 + cmdLineSize = 1; /* final null */ 1.111 + for (arg = argv+1; *arg; arg++) { 1.112 + cmdLineSize += strlen(*arg) + 1; /* space in between */ 1.113 + } 1.114 + *cmdLine = PR_MALLOC(cmdLineSize); 1.115 + if (*cmdLine == NULL) { 1.116 + return -1; 1.117 + } 1.118 + 1.119 + (*cmdLine)[0] = '\0'; 1.120 + 1.121 + for (arg = argv+1; *arg; arg++) { 1.122 + if (arg > argv +1) { 1.123 + strcat(*cmdLine, " "); 1.124 + } 1.125 + strcat(*cmdLine, *arg); 1.126 + } 1.127 + return 0; 1.128 +} 1.129 + 1.130 +/* 1.131 + * Assemble the environment block by concatenating the envp array 1.132 + * (preserving the terminating null byte in each array element) 1.133 + * and adding a null byte at the end. 1.134 + * 1.135 + * Returns 0 on success. The resulting environment block is returned 1.136 + * in *envBlock. Note that if envp is NULL, a NULL pointer is returned 1.137 + * in *envBlock. Returns -1 on failure. 1.138 + */ 1.139 +static int assembleEnvBlock(char **envp, char **envBlock) 1.140 +{ 1.141 + char *p; 1.142 + char *q; 1.143 + char **env; 1.144 + char *curEnv; 1.145 + char *cwdStart, *cwdEnd; 1.146 + int envBlockSize; 1.147 + 1.148 + PPIB ppib = NULL; 1.149 + PTIB ptib = NULL; 1.150 + 1.151 + if (envp == NULL) { 1.152 + *envBlock = NULL; 1.153 + return 0; 1.154 + } 1.155 + 1.156 + if(DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) 1.157 + return -1; 1.158 + 1.159 + curEnv = ppib->pib_pchenv; 1.160 + 1.161 + cwdStart = curEnv; 1.162 + while (*cwdStart) { 1.163 + if (cwdStart[0] == '=' && cwdStart[1] != '\0' 1.164 + && cwdStart[2] == ':' && cwdStart[3] == '=') { 1.165 + break; 1.166 + } 1.167 + cwdStart += strlen(cwdStart) + 1; 1.168 + } 1.169 + cwdEnd = cwdStart; 1.170 + if (*cwdEnd) { 1.171 + cwdEnd += strlen(cwdEnd) + 1; 1.172 + while (*cwdEnd) { 1.173 + if (cwdEnd[0] != '=' || cwdEnd[1] == '\0' 1.174 + || cwdEnd[2] != ':' || cwdEnd[3] != '=') { 1.175 + break; 1.176 + } 1.177 + cwdEnd += strlen(cwdEnd) + 1; 1.178 + } 1.179 + } 1.180 + envBlockSize = cwdEnd - cwdStart; 1.181 + 1.182 + for (env = envp; *env; env++) { 1.183 + envBlockSize += strlen(*env) + 1; 1.184 + } 1.185 + envBlockSize++; 1.186 + 1.187 + p = *envBlock = PR_MALLOC(envBlockSize); 1.188 + if (p == NULL) { 1.189 + return -1; 1.190 + } 1.191 + 1.192 + q = cwdStart; 1.193 + while (q < cwdEnd) { 1.194 + *p++ = *q++; 1.195 + } 1.196 + 1.197 + for (env = envp; *env; env++) { 1.198 + q = *env; 1.199 + while (*q) { 1.200 + *p++ = *q++; 1.201 + } 1.202 + *p++ = '\0'; 1.203 + } 1.204 + *p = '\0'; 1.205 + return 0; 1.206 +} 1.207 + 1.208 +/* 1.209 + * For qsort. We sort (case-insensitive) the environment strings 1.210 + * before generating the environment block. 1.211 + */ 1.212 +static int compare(const void *arg1, const void *arg2) 1.213 +{ 1.214 + return stricmp(* (char**)arg1, * (char**)arg2); 1.215 +} 1.216 + 1.217 +PRProcess * _PR_CreateOS2Process( 1.218 + const char *path, 1.219 + char *const *argv, 1.220 + char *const *envp, 1.221 + const PRProcessAttr *attr) 1.222 +{ 1.223 + PRProcess *proc = NULL; 1.224 + char *cmdLine = NULL; 1.225 + char **newEnvp = NULL; 1.226 + char *envBlock = NULL; 1.227 + 1.228 + STARTDATA startData = {0}; 1.229 + APIRET rc; 1.230 + ULONG ulAppType = 0; 1.231 + PID pid = 0; 1.232 + char *pszComSpec; 1.233 + char pszEXEName[CCHMAXPATH] = ""; 1.234 + char pszFormatString[CCHMAXPATH]; 1.235 + char pszObjectBuffer[CCHMAXPATH]; 1.236 + char *pszFormatResult = NULL; 1.237 + 1.238 + /* 1.239 + * Variables for DosExecPgm 1.240 + */ 1.241 + char szFailed[CCHMAXPATH]; 1.242 + char *pszCmdLine = NULL; 1.243 + RESULTCODES procInfo; 1.244 + HFILE hStdIn = 0, 1.245 + hStdOut = 0, 1.246 + hStdErr = 0; 1.247 + HFILE hStdInSave = -1, 1.248 + hStdOutSave = -1, 1.249 + hStdErrSave = -1; 1.250 + 1.251 + proc = PR_NEW(PRProcess); 1.252 + if (!proc) { 1.253 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.254 + goto errorExit; 1.255 + } 1.256 + 1.257 + if (assembleCmdLine(argv, &cmdLine) == -1) { 1.258 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.259 + goto errorExit; 1.260 + } 1.261 + 1.262 +#ifdef MOZ_OS2_HIGH_MEMORY 1.263 + /* 1.264 + * DosQueryAppType() fails if path (the char* in the first argument) is in 1.265 + * high memory. If that is the case, the following moves it to low memory. 1.266 + */ 1.267 + if ((ULONG)path >= 0x20000000) { 1.268 + size_t len = strlen(path) + 1; 1.269 + char *copy = (char *)alloca(len); 1.270 + memcpy(copy, path, len); 1.271 + path = copy; 1.272 + } 1.273 +#endif 1.274 + 1.275 + if (envp == NULL) { 1.276 + newEnvp = NULL; 1.277 + } else { 1.278 + int i; 1.279 + int numEnv = 0; 1.280 + while (envp[numEnv]) { 1.281 + numEnv++; 1.282 + } 1.283 + newEnvp = (char **) PR_MALLOC((numEnv+1) * sizeof(char *)); 1.284 + for (i = 0; i <= numEnv; i++) { 1.285 + newEnvp[i] = envp[i]; 1.286 + } 1.287 + qsort((void *) newEnvp, (size_t) numEnv, sizeof(char *), compare); 1.288 + } 1.289 + if (assembleEnvBlock(newEnvp, &envBlock) == -1) { 1.290 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.291 + goto errorExit; 1.292 + } 1.293 + 1.294 + rc = DosQueryAppType(path, &ulAppType); 1.295 + if (rc != NO_ERROR) { 1.296 + char *pszDot = strrchr(path, '.'); 1.297 + if (pszDot) { 1.298 + /* If it is a CMD file, launch the users command processor */ 1.299 + if (!stricmp(pszDot, ".cmd")) { 1.300 + rc = DosScanEnv("COMSPEC", (PSZ *)&pszComSpec); 1.301 + if (!rc) { 1.302 + strcpy(pszFormatString, "/C %s %s"); 1.303 + strcpy(pszEXEName, pszComSpec); 1.304 + ulAppType = FAPPTYP_WINDOWCOMPAT; 1.305 + } 1.306 + } 1.307 + } 1.308 + } 1.309 + if (ulAppType == 0) { 1.310 + PR_SetError(PR_UNKNOWN_ERROR, 0); 1.311 + goto errorExit; 1.312 + } 1.313 + 1.314 + if ((ulAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) { 1.315 + startData.SessionType = SSF_TYPE_PM; 1.316 + } 1.317 + else if (ulAppType & FAPPTYP_WINDOWCOMPAT) { 1.318 + startData.SessionType = SSF_TYPE_WINDOWABLEVIO; 1.319 + } 1.320 + else { 1.321 + startData.SessionType = SSF_TYPE_DEFAULT; 1.322 + } 1.323 + 1.324 + if (ulAppType & (FAPPTYP_WINDOWSPROT31 | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSREAL)) 1.325 + { 1.326 + strcpy(pszEXEName, "WINOS2.COM"); 1.327 + startData.SessionType = PROG_31_STDSEAMLESSVDM; 1.328 + strcpy(pszFormatString, "/3 %s %s"); 1.329 + } 1.330 + 1.331 + startData.InheritOpt = SSF_INHERTOPT_SHELL; 1.332 + 1.333 + if (pszEXEName[0]) { 1.334 + pszFormatResult = PR_MALLOC(strlen(pszFormatString)+strlen(path)+strlen(cmdLine)); 1.335 + sprintf(pszFormatResult, pszFormatString, path, cmdLine); 1.336 + startData.PgmInputs = pszFormatResult; 1.337 + } else { 1.338 + strcpy(pszEXEName, path); 1.339 + startData.PgmInputs = cmdLine; 1.340 + } 1.341 + startData.PgmName = pszEXEName; 1.342 + 1.343 + startData.Length = sizeof(startData); 1.344 + startData.Related = SSF_RELATED_INDEPENDENT; 1.345 + startData.ObjectBuffer = pszObjectBuffer; 1.346 + startData.ObjectBuffLen = CCHMAXPATH; 1.347 + startData.Environment = envBlock; 1.348 + 1.349 + if (attr) { 1.350 + /* On OS/2, there is really no way to pass file handles for stdin, 1.351 + * stdout, and stderr to a new process. Instead, we can make it 1.352 + * a child process and make the given file handles a copy of our 1.353 + * stdin, stdout, and stderr. The child process then inherits 1.354 + * ours, and we set ours back. Twisted and gross I know. If you 1.355 + * know a better way, please use it. 1.356 + */ 1.357 + if (attr->stdinFd) { 1.358 + hStdIn = 0; 1.359 + DosDupHandle(hStdIn, &hStdInSave); 1.360 + DosDupHandle((HFILE) attr->stdinFd->secret->md.osfd, &hStdIn); 1.361 + } 1.362 + 1.363 + if (attr->stdoutFd) { 1.364 + hStdOut = 1; 1.365 + DosDupHandle(hStdOut, &hStdOutSave); 1.366 + DosDupHandle((HFILE) attr->stdoutFd->secret->md.osfd, &hStdOut); 1.367 + } 1.368 + 1.369 + if (attr->stderrFd) { 1.370 + hStdErr = 2; 1.371 + DosDupHandle(hStdErr, &hStdErrSave); 1.372 + DosDupHandle((HFILE) attr->stderrFd->secret->md.osfd, &hStdErr); 1.373 + } 1.374 + /* 1.375 + * Build up the Command Line for DosExecPgm 1.376 + */ 1.377 + pszCmdLine = PR_MALLOC(strlen(pszEXEName) + 1.378 + strlen(startData.PgmInputs) + 3); 1.379 + sprintf(pszCmdLine, "%s%c%s%c", pszEXEName, '\0', 1.380 + startData.PgmInputs, '\0'); 1.381 + rc = DosExecPgm(szFailed, 1.382 + CCHMAXPATH, 1.383 + EXEC_ASYNCRESULT, 1.384 + pszCmdLine, 1.385 + envBlock, 1.386 + &procInfo, 1.387 + pszEXEName); 1.388 + PR_DELETE(pszCmdLine); 1.389 + 1.390 + /* Restore our old values. Hope this works */ 1.391 + if (hStdInSave != -1) { 1.392 + DosDupHandle(hStdInSave, &hStdIn); 1.393 + DosClose(hStdInSave); 1.394 + } 1.395 + 1.396 + if (hStdOutSave != -1) { 1.397 + DosDupHandle(hStdOutSave, &hStdOut); 1.398 + DosClose(hStdOutSave); 1.399 + } 1.400 + 1.401 + if (hStdErrSave != -1) { 1.402 + DosDupHandle(hStdErrSave, &hStdErr); 1.403 + DosClose(hStdErrSave); 1.404 + } 1.405 + 1.406 + if (rc != NO_ERROR) { 1.407 + /* XXX what error code? */ 1.408 + PR_SetError(PR_UNKNOWN_ERROR, rc); 1.409 + goto errorExit; 1.410 + } 1.411 + 1.412 + proc->md.pid = procInfo.codeTerminate; 1.413 + } else { 1.414 + /* 1.415 + * If no STDIN/STDOUT redirection is not needed, use DosStartSession 1.416 + * to create a new, independent session 1.417 + */ 1.418 + rc = DosStartSession(&startData, &ulAppType, &pid); 1.419 + 1.420 + if ((rc != NO_ERROR) && (rc != ERROR_SMG_START_IN_BACKGROUND)) { 1.421 + PR_SetError(PR_UNKNOWN_ERROR, rc); 1.422 + goto errorExit; 1.423 + } 1.424 + 1.425 + proc->md.pid = pid; 1.426 + } 1.427 + 1.428 + if (pszFormatResult) { 1.429 + PR_DELETE(pszFormatResult); 1.430 + } 1.431 + 1.432 + PR_DELETE(cmdLine); 1.433 + if (newEnvp) { 1.434 + PR_DELETE(newEnvp); 1.435 + } 1.436 + if (envBlock) { 1.437 + PR_DELETE(envBlock); 1.438 + } 1.439 + return proc; 1.440 + 1.441 +errorExit: 1.442 + if (cmdLine) { 1.443 + PR_DELETE(cmdLine); 1.444 + } 1.445 + if (newEnvp) { 1.446 + PR_DELETE(newEnvp); 1.447 + } 1.448 + if (envBlock) { 1.449 + PR_DELETE(envBlock); 1.450 + } 1.451 + if (proc) { 1.452 + PR_DELETE(proc); 1.453 + } 1.454 + return NULL; 1.455 +} /* _PR_CreateOS2Process */ 1.456 + 1.457 +PRStatus _PR_DetachOS2Process(PRProcess *process) 1.458 +{ 1.459 + /* On OS/2, a process is either created as a child or not. 1.460 + * You can't 'detach' it later on. 1.461 + */ 1.462 + PR_DELETE(process); 1.463 + return PR_SUCCESS; 1.464 +} 1.465 + 1.466 +/* 1.467 + * XXX: This will currently only work on a child process. 1.468 + */ 1.469 +PRStatus _PR_WaitOS2Process(PRProcess *process, 1.470 + PRInt32 *exitCode) 1.471 +{ 1.472 + ULONG ulRetVal; 1.473 + RESULTCODES results; 1.474 + PID pidEnded = 0; 1.475 + 1.476 + ulRetVal = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, 1.477 + &results, 1.478 + &pidEnded, process->md.pid); 1.479 + 1.480 + if (ulRetVal != NO_ERROR) { 1.481 + printf("\nDosWaitChild rc = %lu\n", ulRetVal); 1.482 + PR_SetError(PR_UNKNOWN_ERROR, ulRetVal); 1.483 + return PR_FAILURE; 1.484 + } 1.485 + PR_DELETE(process); 1.486 + return PR_SUCCESS; 1.487 +} 1.488 + 1.489 +PRStatus _PR_KillOS2Process(PRProcess *process) 1.490 +{ 1.491 + ULONG ulRetVal; 1.492 + if ((ulRetVal = DosKillProcess(DKP_PROCESS, process->md.pid)) == NO_ERROR) { 1.493 + return PR_SUCCESS; 1.494 + } 1.495 + PR_SetError(PR_UNKNOWN_ERROR, ulRetVal); 1.496 + return PR_FAILURE; 1.497 +} 1.498 + 1.499 +PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen) 1.500 +{ 1.501 + PRIntn rv; 1.502 + 1.503 + rv = gethostname(name, (PRInt32) namelen); 1.504 + if (0 == rv) { 1.505 + return PR_SUCCESS; 1.506 + } 1.507 + _PR_MD_MAP_GETHOSTNAME_ERROR(sock_errno()); 1.508 + return PR_FAILURE; 1.509 +} 1.510 + 1.511 +void 1.512 +_PR_MD_WAKEUP_CPUS( void ) 1.513 +{ 1.514 + return; 1.515 +} 1.516 + 1.517 +/* 1.518 + ********************************************************************** 1.519 + * 1.520 + * Memory-mapped files 1.521 + * 1.522 + * A credible emulation of memory-mapped i/o on OS/2 would require 1.523 + * an exception-handler on each thread that might access the mapped 1.524 + * memory. In the Mozilla environment, that would be impractical. 1.525 + * Instead, the following simulates those modes which don't modify 1.526 + * the mapped file. It reads the entire mapped file segment at once 1.527 + * when MemMap is called, and frees it on MemUnmap. CreateFileMap 1.528 + * only does sanity-checks, while CloseFileMap does almost nothing. 1.529 + * 1.530 + ********************************************************************** 1.531 + */ 1.532 + 1.533 +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) 1.534 +{ 1.535 + PRFileInfo64 info; 1.536 + 1.537 + /* assert on PR_PROT_READWRITE which modifies the underlying file */ 1.538 + PR_ASSERT(fmap->prot == PR_PROT_READONLY || 1.539 + fmap->prot == PR_PROT_WRITECOPY); 1.540 + if (fmap->prot != PR_PROT_READONLY && 1.541 + fmap->prot != PR_PROT_WRITECOPY) { 1.542 + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 1.543 + return PR_FAILURE; 1.544 + } 1.545 + if (PR_GetOpenFileInfo64(fmap->fd, &info) == PR_FAILURE) { 1.546 + return PR_FAILURE; 1.547 + } 1.548 + /* reject zero-byte mappings & zero-byte files */ 1.549 + if (!size || !info.size) { 1.550 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.551 + return PR_FAILURE; 1.552 + } 1.553 + /* file size rounded up to the next page boundary */ 1.554 + fmap->md.maxExtent = (info.size + 0xfff) & ~(0xfff); 1.555 + 1.556 + return PR_SUCCESS; 1.557 +} 1.558 + 1.559 +PRInt32 _MD_GetMemMapAlignment(void) 1.560 +{ 1.561 + /* OS/2 pages are 4k */ 1.562 + return 0x1000; 1.563 +} 1.564 + 1.565 +void * _MD_MemMap(PRFileMap *fmap, PROffset64 offset, PRUint32 len) 1.566 +{ 1.567 + PRUint32 rv; 1.568 + void *addr; 1.569 + 1.570 + /* prevent mappings beyond EOF + remainder of page */ 1.571 + if (offset + len > fmap->md.maxExtent) { 1.572 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.573 + return NULL; 1.574 + } 1.575 + if (PR_Seek64(fmap->fd, offset, PR_SEEK_SET) == -1) { 1.576 + return NULL; 1.577 + } 1.578 + /* try for high memory, fall back to low memory if hi-mem fails */ 1.579 + rv = DosAllocMem(&addr, len, OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE); 1.580 + if (rv) { 1.581 + rv = DosAllocMem(&addr, len, PAG_COMMIT | PAG_READ | PAG_WRITE); 1.582 + if (rv) { 1.583 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, rv); 1.584 + return NULL; 1.585 + } 1.586 + } 1.587 + if (PR_Read(fmap->fd, addr, len) == -1) { 1.588 + DosFreeMem(addr); 1.589 + return NULL; 1.590 + } 1.591 + /* don't permit writes if readonly */ 1.592 + if (fmap->prot == PR_PROT_READONLY) { 1.593 + rv = DosSetMem(addr, len, PAG_READ); 1.594 + if (rv) { 1.595 + DosFreeMem(addr); 1.596 + PR_SetError(PR_UNKNOWN_ERROR, rv); 1.597 + return NULL; 1.598 + } 1.599 + } 1.600 + return addr; 1.601 +} 1.602 + 1.603 +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) 1.604 +{ 1.605 + PRUint32 rv; 1.606 + 1.607 + /* we just have to trust that addr & len are those used by MemMap */ 1.608 + rv = DosFreeMem(addr); 1.609 + if (rv) { 1.610 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv); 1.611 + return PR_FAILURE; 1.612 + } 1.613 + return PR_SUCCESS; 1.614 +} 1.615 + 1.616 +PRStatus _MD_CloseFileMap(PRFileMap *fmap) 1.617 +{ 1.618 + /* nothing to do except free the PRFileMap struct */ 1.619 + PR_Free(fmap); 1.620 + return PR_SUCCESS; 1.621 +} 1.622 +