nsprpub/pr/src/md/os2/os2misc.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 * os2misc.c
michael@0 8 *
michael@0 9 */
michael@0 10
michael@0 11 #ifdef MOZ_OS2_HIGH_MEMORY
michael@0 12 /* os2safe.h has to be included before os2.h, needed for high mem */
michael@0 13 #include <os2safe.h>
michael@0 14 #endif
michael@0 15
michael@0 16 #include <string.h>
michael@0 17 #include "primpl.h"
michael@0 18
michael@0 19 extern int _CRT_init(void);
michael@0 20 extern void _CRT_term(void);
michael@0 21 extern void __ctordtorInit(int flag);
michael@0 22 extern void __ctordtorTerm(int flag);
michael@0 23
michael@0 24 char *
michael@0 25 _PR_MD_GET_ENV(const char *name)
michael@0 26 {
michael@0 27 return getenv(name);
michael@0 28 }
michael@0 29
michael@0 30 PRIntn
michael@0 31 _PR_MD_PUT_ENV(const char *name)
michael@0 32 {
michael@0 33 return putenv(name);
michael@0 34 }
michael@0 35
michael@0 36
michael@0 37 /*
michael@0 38 **************************************************************************
michael@0 39 **************************************************************************
michael@0 40 **
michael@0 41 ** Date and time routines
michael@0 42 **
michael@0 43 **************************************************************************
michael@0 44 **************************************************************************
michael@0 45 */
michael@0 46
michael@0 47 #include <sys/timeb.h>
michael@0 48 /*
michael@0 49 *-----------------------------------------------------------------------
michael@0 50 *
michael@0 51 * PR_Now --
michael@0 52 *
michael@0 53 * Returns the current time in microseconds since the epoch.
michael@0 54 * The epoch is midnight January 1, 1970 GMT.
michael@0 55 * The implementation is machine dependent. This is the
michael@0 56 * implementation for OS/2.
michael@0 57 * Cf. time_t time(time_t *tp)
michael@0 58 *
michael@0 59 *-----------------------------------------------------------------------
michael@0 60 */
michael@0 61
michael@0 62 PR_IMPLEMENT(PRTime)
michael@0 63 PR_Now(void)
michael@0 64 {
michael@0 65 PRInt64 s, ms, ms2us, s2us;
michael@0 66 struct timeb b;
michael@0 67
michael@0 68 ftime(&b);
michael@0 69 LL_I2L(ms2us, PR_USEC_PER_MSEC);
michael@0 70 LL_I2L(s2us, PR_USEC_PER_SEC);
michael@0 71 LL_I2L(s, b.time);
michael@0 72 LL_I2L(ms, b.millitm);
michael@0 73 LL_MUL(ms, ms, ms2us);
michael@0 74 LL_MUL(s, s, s2us);
michael@0 75 LL_ADD(s, s, ms);
michael@0 76 return s;
michael@0 77 }
michael@0 78
michael@0 79
michael@0 80 /*
michael@0 81 ***********************************************************************
michael@0 82 ***********************************************************************
michael@0 83 *
michael@0 84 * Process creation routines
michael@0 85 *
michael@0 86 ***********************************************************************
michael@0 87 ***********************************************************************
michael@0 88 */
michael@0 89
michael@0 90 /*
michael@0 91 * Assemble the command line by concatenating the argv array.
michael@0 92 * Special characters intentionally do not get escaped, and it is
michael@0 93 * expected that the caller wraps arguments in quotes if needed
michael@0 94 * (e.g. for filename with spaces).
michael@0 95 *
michael@0 96 * On success, this function returns 0 and the resulting command
michael@0 97 * line is returned in *cmdLine. On failure, it returns -1.
michael@0 98 */
michael@0 99 static int assembleCmdLine(char *const *argv, char **cmdLine)
michael@0 100 {
michael@0 101 char *const *arg;
michael@0 102 int cmdLineSize;
michael@0 103
michael@0 104 /*
michael@0 105 * Find out how large the command line buffer should be.
michael@0 106 */
michael@0 107 cmdLineSize = 1; /* final null */
michael@0 108 for (arg = argv+1; *arg; arg++) {
michael@0 109 cmdLineSize += strlen(*arg) + 1; /* space in between */
michael@0 110 }
michael@0 111 *cmdLine = PR_MALLOC(cmdLineSize);
michael@0 112 if (*cmdLine == NULL) {
michael@0 113 return -1;
michael@0 114 }
michael@0 115
michael@0 116 (*cmdLine)[0] = '\0';
michael@0 117
michael@0 118 for (arg = argv+1; *arg; arg++) {
michael@0 119 if (arg > argv +1) {
michael@0 120 strcat(*cmdLine, " ");
michael@0 121 }
michael@0 122 strcat(*cmdLine, *arg);
michael@0 123 }
michael@0 124 return 0;
michael@0 125 }
michael@0 126
michael@0 127 /*
michael@0 128 * Assemble the environment block by concatenating the envp array
michael@0 129 * (preserving the terminating null byte in each array element)
michael@0 130 * and adding a null byte at the end.
michael@0 131 *
michael@0 132 * Returns 0 on success. The resulting environment block is returned
michael@0 133 * in *envBlock. Note that if envp is NULL, a NULL pointer is returned
michael@0 134 * in *envBlock. Returns -1 on failure.
michael@0 135 */
michael@0 136 static int assembleEnvBlock(char **envp, char **envBlock)
michael@0 137 {
michael@0 138 char *p;
michael@0 139 char *q;
michael@0 140 char **env;
michael@0 141 char *curEnv;
michael@0 142 char *cwdStart, *cwdEnd;
michael@0 143 int envBlockSize;
michael@0 144
michael@0 145 PPIB ppib = NULL;
michael@0 146 PTIB ptib = NULL;
michael@0 147
michael@0 148 if (envp == NULL) {
michael@0 149 *envBlock = NULL;
michael@0 150 return 0;
michael@0 151 }
michael@0 152
michael@0 153 if(DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR)
michael@0 154 return -1;
michael@0 155
michael@0 156 curEnv = ppib->pib_pchenv;
michael@0 157
michael@0 158 cwdStart = curEnv;
michael@0 159 while (*cwdStart) {
michael@0 160 if (cwdStart[0] == '=' && cwdStart[1] != '\0'
michael@0 161 && cwdStart[2] == ':' && cwdStart[3] == '=') {
michael@0 162 break;
michael@0 163 }
michael@0 164 cwdStart += strlen(cwdStart) + 1;
michael@0 165 }
michael@0 166 cwdEnd = cwdStart;
michael@0 167 if (*cwdEnd) {
michael@0 168 cwdEnd += strlen(cwdEnd) + 1;
michael@0 169 while (*cwdEnd) {
michael@0 170 if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
michael@0 171 || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
michael@0 172 break;
michael@0 173 }
michael@0 174 cwdEnd += strlen(cwdEnd) + 1;
michael@0 175 }
michael@0 176 }
michael@0 177 envBlockSize = cwdEnd - cwdStart;
michael@0 178
michael@0 179 for (env = envp; *env; env++) {
michael@0 180 envBlockSize += strlen(*env) + 1;
michael@0 181 }
michael@0 182 envBlockSize++;
michael@0 183
michael@0 184 p = *envBlock = PR_MALLOC(envBlockSize);
michael@0 185 if (p == NULL) {
michael@0 186 return -1;
michael@0 187 }
michael@0 188
michael@0 189 q = cwdStart;
michael@0 190 while (q < cwdEnd) {
michael@0 191 *p++ = *q++;
michael@0 192 }
michael@0 193
michael@0 194 for (env = envp; *env; env++) {
michael@0 195 q = *env;
michael@0 196 while (*q) {
michael@0 197 *p++ = *q++;
michael@0 198 }
michael@0 199 *p++ = '\0';
michael@0 200 }
michael@0 201 *p = '\0';
michael@0 202 return 0;
michael@0 203 }
michael@0 204
michael@0 205 /*
michael@0 206 * For qsort. We sort (case-insensitive) the environment strings
michael@0 207 * before generating the environment block.
michael@0 208 */
michael@0 209 static int compare(const void *arg1, const void *arg2)
michael@0 210 {
michael@0 211 return stricmp(* (char**)arg1, * (char**)arg2);
michael@0 212 }
michael@0 213
michael@0 214 PRProcess * _PR_CreateOS2Process(
michael@0 215 const char *path,
michael@0 216 char *const *argv,
michael@0 217 char *const *envp,
michael@0 218 const PRProcessAttr *attr)
michael@0 219 {
michael@0 220 PRProcess *proc = NULL;
michael@0 221 char *cmdLine = NULL;
michael@0 222 char **newEnvp = NULL;
michael@0 223 char *envBlock = NULL;
michael@0 224
michael@0 225 STARTDATA startData = {0};
michael@0 226 APIRET rc;
michael@0 227 ULONG ulAppType = 0;
michael@0 228 PID pid = 0;
michael@0 229 char *pszComSpec;
michael@0 230 char pszEXEName[CCHMAXPATH] = "";
michael@0 231 char pszFormatString[CCHMAXPATH];
michael@0 232 char pszObjectBuffer[CCHMAXPATH];
michael@0 233 char *pszFormatResult = NULL;
michael@0 234
michael@0 235 /*
michael@0 236 * Variables for DosExecPgm
michael@0 237 */
michael@0 238 char szFailed[CCHMAXPATH];
michael@0 239 char *pszCmdLine = NULL;
michael@0 240 RESULTCODES procInfo;
michael@0 241 HFILE hStdIn = 0,
michael@0 242 hStdOut = 0,
michael@0 243 hStdErr = 0;
michael@0 244 HFILE hStdInSave = -1,
michael@0 245 hStdOutSave = -1,
michael@0 246 hStdErrSave = -1;
michael@0 247
michael@0 248 proc = PR_NEW(PRProcess);
michael@0 249 if (!proc) {
michael@0 250 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
michael@0 251 goto errorExit;
michael@0 252 }
michael@0 253
michael@0 254 if (assembleCmdLine(argv, &cmdLine) == -1) {
michael@0 255 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
michael@0 256 goto errorExit;
michael@0 257 }
michael@0 258
michael@0 259 #ifdef MOZ_OS2_HIGH_MEMORY
michael@0 260 /*
michael@0 261 * DosQueryAppType() fails if path (the char* in the first argument) is in
michael@0 262 * high memory. If that is the case, the following moves it to low memory.
michael@0 263 */
michael@0 264 if ((ULONG)path >= 0x20000000) {
michael@0 265 size_t len = strlen(path) + 1;
michael@0 266 char *copy = (char *)alloca(len);
michael@0 267 memcpy(copy, path, len);
michael@0 268 path = copy;
michael@0 269 }
michael@0 270 #endif
michael@0 271
michael@0 272 if (envp == NULL) {
michael@0 273 newEnvp = NULL;
michael@0 274 } else {
michael@0 275 int i;
michael@0 276 int numEnv = 0;
michael@0 277 while (envp[numEnv]) {
michael@0 278 numEnv++;
michael@0 279 }
michael@0 280 newEnvp = (char **) PR_MALLOC((numEnv+1) * sizeof(char *));
michael@0 281 for (i = 0; i <= numEnv; i++) {
michael@0 282 newEnvp[i] = envp[i];
michael@0 283 }
michael@0 284 qsort((void *) newEnvp, (size_t) numEnv, sizeof(char *), compare);
michael@0 285 }
michael@0 286 if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
michael@0 287 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
michael@0 288 goto errorExit;
michael@0 289 }
michael@0 290
michael@0 291 rc = DosQueryAppType(path, &ulAppType);
michael@0 292 if (rc != NO_ERROR) {
michael@0 293 char *pszDot = strrchr(path, '.');
michael@0 294 if (pszDot) {
michael@0 295 /* If it is a CMD file, launch the users command processor */
michael@0 296 if (!stricmp(pszDot, ".cmd")) {
michael@0 297 rc = DosScanEnv("COMSPEC", (PSZ *)&pszComSpec);
michael@0 298 if (!rc) {
michael@0 299 strcpy(pszFormatString, "/C %s %s");
michael@0 300 strcpy(pszEXEName, pszComSpec);
michael@0 301 ulAppType = FAPPTYP_WINDOWCOMPAT;
michael@0 302 }
michael@0 303 }
michael@0 304 }
michael@0 305 }
michael@0 306 if (ulAppType == 0) {
michael@0 307 PR_SetError(PR_UNKNOWN_ERROR, 0);
michael@0 308 goto errorExit;
michael@0 309 }
michael@0 310
michael@0 311 if ((ulAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) {
michael@0 312 startData.SessionType = SSF_TYPE_PM;
michael@0 313 }
michael@0 314 else if (ulAppType & FAPPTYP_WINDOWCOMPAT) {
michael@0 315 startData.SessionType = SSF_TYPE_WINDOWABLEVIO;
michael@0 316 }
michael@0 317 else {
michael@0 318 startData.SessionType = SSF_TYPE_DEFAULT;
michael@0 319 }
michael@0 320
michael@0 321 if (ulAppType & (FAPPTYP_WINDOWSPROT31 | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSREAL))
michael@0 322 {
michael@0 323 strcpy(pszEXEName, "WINOS2.COM");
michael@0 324 startData.SessionType = PROG_31_STDSEAMLESSVDM;
michael@0 325 strcpy(pszFormatString, "/3 %s %s");
michael@0 326 }
michael@0 327
michael@0 328 startData.InheritOpt = SSF_INHERTOPT_SHELL;
michael@0 329
michael@0 330 if (pszEXEName[0]) {
michael@0 331 pszFormatResult = PR_MALLOC(strlen(pszFormatString)+strlen(path)+strlen(cmdLine));
michael@0 332 sprintf(pszFormatResult, pszFormatString, path, cmdLine);
michael@0 333 startData.PgmInputs = pszFormatResult;
michael@0 334 } else {
michael@0 335 strcpy(pszEXEName, path);
michael@0 336 startData.PgmInputs = cmdLine;
michael@0 337 }
michael@0 338 startData.PgmName = pszEXEName;
michael@0 339
michael@0 340 startData.Length = sizeof(startData);
michael@0 341 startData.Related = SSF_RELATED_INDEPENDENT;
michael@0 342 startData.ObjectBuffer = pszObjectBuffer;
michael@0 343 startData.ObjectBuffLen = CCHMAXPATH;
michael@0 344 startData.Environment = envBlock;
michael@0 345
michael@0 346 if (attr) {
michael@0 347 /* On OS/2, there is really no way to pass file handles for stdin,
michael@0 348 * stdout, and stderr to a new process. Instead, we can make it
michael@0 349 * a child process and make the given file handles a copy of our
michael@0 350 * stdin, stdout, and stderr. The child process then inherits
michael@0 351 * ours, and we set ours back. Twisted and gross I know. If you
michael@0 352 * know a better way, please use it.
michael@0 353 */
michael@0 354 if (attr->stdinFd) {
michael@0 355 hStdIn = 0;
michael@0 356 DosDupHandle(hStdIn, &hStdInSave);
michael@0 357 DosDupHandle((HFILE) attr->stdinFd->secret->md.osfd, &hStdIn);
michael@0 358 }
michael@0 359
michael@0 360 if (attr->stdoutFd) {
michael@0 361 hStdOut = 1;
michael@0 362 DosDupHandle(hStdOut, &hStdOutSave);
michael@0 363 DosDupHandle((HFILE) attr->stdoutFd->secret->md.osfd, &hStdOut);
michael@0 364 }
michael@0 365
michael@0 366 if (attr->stderrFd) {
michael@0 367 hStdErr = 2;
michael@0 368 DosDupHandle(hStdErr, &hStdErrSave);
michael@0 369 DosDupHandle((HFILE) attr->stderrFd->secret->md.osfd, &hStdErr);
michael@0 370 }
michael@0 371 /*
michael@0 372 * Build up the Command Line for DosExecPgm
michael@0 373 */
michael@0 374 pszCmdLine = PR_MALLOC(strlen(pszEXEName) +
michael@0 375 strlen(startData.PgmInputs) + 3);
michael@0 376 sprintf(pszCmdLine, "%s%c%s%c", pszEXEName, '\0',
michael@0 377 startData.PgmInputs, '\0');
michael@0 378 rc = DosExecPgm(szFailed,
michael@0 379 CCHMAXPATH,
michael@0 380 EXEC_ASYNCRESULT,
michael@0 381 pszCmdLine,
michael@0 382 envBlock,
michael@0 383 &procInfo,
michael@0 384 pszEXEName);
michael@0 385 PR_DELETE(pszCmdLine);
michael@0 386
michael@0 387 /* Restore our old values. Hope this works */
michael@0 388 if (hStdInSave != -1) {
michael@0 389 DosDupHandle(hStdInSave, &hStdIn);
michael@0 390 DosClose(hStdInSave);
michael@0 391 }
michael@0 392
michael@0 393 if (hStdOutSave != -1) {
michael@0 394 DosDupHandle(hStdOutSave, &hStdOut);
michael@0 395 DosClose(hStdOutSave);
michael@0 396 }
michael@0 397
michael@0 398 if (hStdErrSave != -1) {
michael@0 399 DosDupHandle(hStdErrSave, &hStdErr);
michael@0 400 DosClose(hStdErrSave);
michael@0 401 }
michael@0 402
michael@0 403 if (rc != NO_ERROR) {
michael@0 404 /* XXX what error code? */
michael@0 405 PR_SetError(PR_UNKNOWN_ERROR, rc);
michael@0 406 goto errorExit;
michael@0 407 }
michael@0 408
michael@0 409 proc->md.pid = procInfo.codeTerminate;
michael@0 410 } else {
michael@0 411 /*
michael@0 412 * If no STDIN/STDOUT redirection is not needed, use DosStartSession
michael@0 413 * to create a new, independent session
michael@0 414 */
michael@0 415 rc = DosStartSession(&startData, &ulAppType, &pid);
michael@0 416
michael@0 417 if ((rc != NO_ERROR) && (rc != ERROR_SMG_START_IN_BACKGROUND)) {
michael@0 418 PR_SetError(PR_UNKNOWN_ERROR, rc);
michael@0 419 goto errorExit;
michael@0 420 }
michael@0 421
michael@0 422 proc->md.pid = pid;
michael@0 423 }
michael@0 424
michael@0 425 if (pszFormatResult) {
michael@0 426 PR_DELETE(pszFormatResult);
michael@0 427 }
michael@0 428
michael@0 429 PR_DELETE(cmdLine);
michael@0 430 if (newEnvp) {
michael@0 431 PR_DELETE(newEnvp);
michael@0 432 }
michael@0 433 if (envBlock) {
michael@0 434 PR_DELETE(envBlock);
michael@0 435 }
michael@0 436 return proc;
michael@0 437
michael@0 438 errorExit:
michael@0 439 if (cmdLine) {
michael@0 440 PR_DELETE(cmdLine);
michael@0 441 }
michael@0 442 if (newEnvp) {
michael@0 443 PR_DELETE(newEnvp);
michael@0 444 }
michael@0 445 if (envBlock) {
michael@0 446 PR_DELETE(envBlock);
michael@0 447 }
michael@0 448 if (proc) {
michael@0 449 PR_DELETE(proc);
michael@0 450 }
michael@0 451 return NULL;
michael@0 452 } /* _PR_CreateOS2Process */
michael@0 453
michael@0 454 PRStatus _PR_DetachOS2Process(PRProcess *process)
michael@0 455 {
michael@0 456 /* On OS/2, a process is either created as a child or not.
michael@0 457 * You can't 'detach' it later on.
michael@0 458 */
michael@0 459 PR_DELETE(process);
michael@0 460 return PR_SUCCESS;
michael@0 461 }
michael@0 462
michael@0 463 /*
michael@0 464 * XXX: This will currently only work on a child process.
michael@0 465 */
michael@0 466 PRStatus _PR_WaitOS2Process(PRProcess *process,
michael@0 467 PRInt32 *exitCode)
michael@0 468 {
michael@0 469 ULONG ulRetVal;
michael@0 470 RESULTCODES results;
michael@0 471 PID pidEnded = 0;
michael@0 472
michael@0 473 ulRetVal = DosWaitChild(DCWA_PROCESS, DCWW_WAIT,
michael@0 474 &results,
michael@0 475 &pidEnded, process->md.pid);
michael@0 476
michael@0 477 if (ulRetVal != NO_ERROR) {
michael@0 478 printf("\nDosWaitChild rc = %lu\n", ulRetVal);
michael@0 479 PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
michael@0 480 return PR_FAILURE;
michael@0 481 }
michael@0 482 PR_DELETE(process);
michael@0 483 return PR_SUCCESS;
michael@0 484 }
michael@0 485
michael@0 486 PRStatus _PR_KillOS2Process(PRProcess *process)
michael@0 487 {
michael@0 488 ULONG ulRetVal;
michael@0 489 if ((ulRetVal = DosKillProcess(DKP_PROCESS, process->md.pid)) == NO_ERROR) {
michael@0 490 return PR_SUCCESS;
michael@0 491 }
michael@0 492 PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
michael@0 493 return PR_FAILURE;
michael@0 494 }
michael@0 495
michael@0 496 PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen)
michael@0 497 {
michael@0 498 PRIntn rv;
michael@0 499
michael@0 500 rv = gethostname(name, (PRInt32) namelen);
michael@0 501 if (0 == rv) {
michael@0 502 return PR_SUCCESS;
michael@0 503 }
michael@0 504 _PR_MD_MAP_GETHOSTNAME_ERROR(sock_errno());
michael@0 505 return PR_FAILURE;
michael@0 506 }
michael@0 507
michael@0 508 void
michael@0 509 _PR_MD_WAKEUP_CPUS( void )
michael@0 510 {
michael@0 511 return;
michael@0 512 }
michael@0 513
michael@0 514 /*
michael@0 515 **********************************************************************
michael@0 516 *
michael@0 517 * Memory-mapped files
michael@0 518 *
michael@0 519 * A credible emulation of memory-mapped i/o on OS/2 would require
michael@0 520 * an exception-handler on each thread that might access the mapped
michael@0 521 * memory. In the Mozilla environment, that would be impractical.
michael@0 522 * Instead, the following simulates those modes which don't modify
michael@0 523 * the mapped file. It reads the entire mapped file segment at once
michael@0 524 * when MemMap is called, and frees it on MemUnmap. CreateFileMap
michael@0 525 * only does sanity-checks, while CloseFileMap does almost nothing.
michael@0 526 *
michael@0 527 **********************************************************************
michael@0 528 */
michael@0 529
michael@0 530 PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
michael@0 531 {
michael@0 532 PRFileInfo64 info;
michael@0 533
michael@0 534 /* assert on PR_PROT_READWRITE which modifies the underlying file */
michael@0 535 PR_ASSERT(fmap->prot == PR_PROT_READONLY ||
michael@0 536 fmap->prot == PR_PROT_WRITECOPY);
michael@0 537 if (fmap->prot != PR_PROT_READONLY &&
michael@0 538 fmap->prot != PR_PROT_WRITECOPY) {
michael@0 539 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
michael@0 540 return PR_FAILURE;
michael@0 541 }
michael@0 542 if (PR_GetOpenFileInfo64(fmap->fd, &info) == PR_FAILURE) {
michael@0 543 return PR_FAILURE;
michael@0 544 }
michael@0 545 /* reject zero-byte mappings & zero-byte files */
michael@0 546 if (!size || !info.size) {
michael@0 547 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
michael@0 548 return PR_FAILURE;
michael@0 549 }
michael@0 550 /* file size rounded up to the next page boundary */
michael@0 551 fmap->md.maxExtent = (info.size + 0xfff) & ~(0xfff);
michael@0 552
michael@0 553 return PR_SUCCESS;
michael@0 554 }
michael@0 555
michael@0 556 PRInt32 _MD_GetMemMapAlignment(void)
michael@0 557 {
michael@0 558 /* OS/2 pages are 4k */
michael@0 559 return 0x1000;
michael@0 560 }
michael@0 561
michael@0 562 void * _MD_MemMap(PRFileMap *fmap, PROffset64 offset, PRUint32 len)
michael@0 563 {
michael@0 564 PRUint32 rv;
michael@0 565 void *addr;
michael@0 566
michael@0 567 /* prevent mappings beyond EOF + remainder of page */
michael@0 568 if (offset + len > fmap->md.maxExtent) {
michael@0 569 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
michael@0 570 return NULL;
michael@0 571 }
michael@0 572 if (PR_Seek64(fmap->fd, offset, PR_SEEK_SET) == -1) {
michael@0 573 return NULL;
michael@0 574 }
michael@0 575 /* try for high memory, fall back to low memory if hi-mem fails */
michael@0 576 rv = DosAllocMem(&addr, len, OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE);
michael@0 577 if (rv) {
michael@0 578 rv = DosAllocMem(&addr, len, PAG_COMMIT | PAG_READ | PAG_WRITE);
michael@0 579 if (rv) {
michael@0 580 PR_SetError(PR_OUT_OF_MEMORY_ERROR, rv);
michael@0 581 return NULL;
michael@0 582 }
michael@0 583 }
michael@0 584 if (PR_Read(fmap->fd, addr, len) == -1) {
michael@0 585 DosFreeMem(addr);
michael@0 586 return NULL;
michael@0 587 }
michael@0 588 /* don't permit writes if readonly */
michael@0 589 if (fmap->prot == PR_PROT_READONLY) {
michael@0 590 rv = DosSetMem(addr, len, PAG_READ);
michael@0 591 if (rv) {
michael@0 592 DosFreeMem(addr);
michael@0 593 PR_SetError(PR_UNKNOWN_ERROR, rv);
michael@0 594 return NULL;
michael@0 595 }
michael@0 596 }
michael@0 597 return addr;
michael@0 598 }
michael@0 599
michael@0 600 PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
michael@0 601 {
michael@0 602 PRUint32 rv;
michael@0 603
michael@0 604 /* we just have to trust that addr & len are those used by MemMap */
michael@0 605 rv = DosFreeMem(addr);
michael@0 606 if (rv) {
michael@0 607 PR_SetError(PR_INVALID_ARGUMENT_ERROR, rv);
michael@0 608 return PR_FAILURE;
michael@0 609 }
michael@0 610 return PR_SUCCESS;
michael@0 611 }
michael@0 612
michael@0 613 PRStatus _MD_CloseFileMap(PRFileMap *fmap)
michael@0 614 {
michael@0 615 /* nothing to do except free the PRFileMap struct */
michael@0 616 PR_Free(fmap);
michael@0 617 return PR_SUCCESS;
michael@0 618 }
michael@0 619

mercurial