home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / windows / ntmisc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  17.2 KB  |  604 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * ntmisc.c
  21.  *
  22.  */
  23.  
  24. #include "primpl.h"
  25.  
  26. char *_PR_MD_GET_ENV(const char *name)
  27. {
  28.     return getenv(name);
  29. }
  30.  
  31. PRIntn _PR_MD_PUT_ENV(const char *name)
  32. {
  33.     return putenv(name);
  34. }
  35.  
  36.  
  37. /*
  38.  **************************************************************************
  39.  **************************************************************************
  40.  **
  41.  **     Date and time routines
  42.  **
  43.  **************************************************************************
  44.  **************************************************************************
  45.  */
  46.  
  47. #include <sys/timeb.h>
  48.  
  49. /*
  50.  *-----------------------------------------------------------------------
  51.  *
  52.  * PR_Now --
  53.  *
  54.  *     Returns the current time in microseconds since the epoch.
  55.  *     The epoch is midnight January 1, 1970 GMT.
  56.  *     The implementation is machine dependent.  This is the
  57.  *     implementation for Windows.
  58.  *     Cf. time_t time(time_t *tp)
  59.  *
  60.  *-----------------------------------------------------------------------
  61.  */
  62.  
  63. PRTime
  64. PR_Now(void)
  65. {
  66.     PRInt64 s, ms, ms2us, s2us;
  67.     struct timeb b;
  68.  
  69.     ftime(&b);
  70.     LL_I2L(ms2us, PR_USEC_PER_MSEC);
  71.     LL_I2L(s2us, PR_USEC_PER_SEC);
  72.     LL_I2L(s, b.time);
  73.     LL_I2L(ms, b.millitm);
  74.     LL_MUL(ms, ms, ms2us);
  75.     LL_MUL(s, s, s2us);
  76.     LL_ADD(s, s, ms);
  77.     return s;       
  78. }
  79.  
  80. /*
  81.  * The following code works around a bug in NT (Netscape Bugsplat
  82.  * Defect ID 47942).
  83.  *
  84.  * In Windows NT 3.51 and 4.0, if the local time zone does not practice
  85.  * daylight savings time, e.g., Arizona, Taiwan, and Japan, the global
  86.  * variables that _ftime() and localtime() depend on have the wrong
  87.  * default values:
  88.  *     _tzname[0]  "PST"
  89.  *     _tzname[1]  "PDT"
  90.  *     _daylight   1
  91.  *     _timezone   28800
  92.  *
  93.  * So at startup time, we need to invoke _PR_Win32InitTimeZone(), which
  94.  * on NT sets these global variables to the correct values (obtained by
  95.  * calling GetTimeZoneInformation().
  96.  */
  97.  
  98. #include <time.h>     /* for _tzname, _daylight, _timezone */
  99.  
  100. void
  101. _PR_Win32InitTimeZone(void)
  102. {
  103.     OSVERSIONINFO version;
  104.     TIME_ZONE_INFORMATION tzinfo;
  105.  
  106.     version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  107.     if (GetVersionEx(&version) != FALSE) {
  108.         /* Only Windows NT needs this hack */
  109.         if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  110.             return;
  111.         }
  112.     }
  113.  
  114.     if (GetTimeZoneInformation(&tzinfo) == 0xffffffff) {
  115.         return;  /* not much we can do if this failed */
  116.     }
  117.  
  118.     /* 
  119.      * I feel nervous about modifying these globals.  I hope that no
  120.      * other thread is reading or modifying these globals simultaneously
  121.      * during nspr initialization.
  122.      *
  123.      * I am assuming that _tzname[0] and _tzname[1] point to static buffers
  124.      * and that the buffers are at least 32 byte long.  My experiments show
  125.      * this is true, but of course this is undocumented.  --wtc
  126.      *
  127.      * Convert time zone names from WCHAR to CHAR and copy them to
  128.      * the static buffers pointed to by _tzname[0] and _tzname[1].
  129.      * Ignore conversion errors, because it is _timezone and _daylight
  130.      * that _ftime() and localtime() really depend on.
  131.      */
  132.  
  133.     WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1, _tzname[0],
  134.             32, NULL, NULL);
  135.     WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1, _tzname[1],
  136.             32, NULL, NULL);
  137.  
  138.     /* _timezone is in seconds.  tzinfo.Bias is in minutes. */
  139.  
  140.     _timezone = tzinfo.Bias * 60;
  141.     _daylight = tzinfo.DaylightBias ? 1 : 0;
  142.     return;
  143. }
  144.  
  145. /*
  146.  ***********************************************************************
  147.  ***********************************************************************
  148.  *
  149.  * Process creation routines
  150.  *
  151.  ***********************************************************************
  152.  ***********************************************************************
  153.  */
  154.  
  155. /*
  156.  * Assemble the command line by concatenating the argv array.
  157.  * On success, this function returns 0 and the resulting command
  158.  * line is returned in *cmdLine.  On failure, it returns -1.
  159.  */
  160. static int assembleCmdLine(char *const *argv, char **cmdLine)
  161. {
  162.     char *const *arg;
  163.     char *p, *q;
  164.     int cmdLineSize;
  165.     int numBackslashes;
  166.     int i;
  167.     int argNeedQuotes;
  168.  
  169.     /*
  170.      * Find out how large the command line buffer should be.
  171.      */
  172.     cmdLineSize = 0;
  173.     for (arg = argv; *arg; arg++) {
  174.         /*
  175.          * \ and " need to be escaped by a \.  In the worst case,
  176.          * every character is a \ or ", so the string of length
  177.          * may double.  If we quote an argument, that needs two ".
  178.          * Finally, we need a space between arguments, and
  179.          * a null byte at the end of command line.
  180.          */
  181.         cmdLineSize += 2 * strlen(*arg)  /* \ and " need to be escaped */
  182.                 + 2                      /* we quote every argument */
  183.                 + 1;                     /* space in between, or final null */
  184.     }
  185.     p = *cmdLine = PR_MALLOC(cmdLineSize);
  186.     if (p == NULL) {
  187.         return -1;
  188.     }
  189.  
  190.     for (arg = argv; *arg; arg++) {
  191.         /* Add a space to separates the arguments */
  192.         if (arg != argv) {
  193.             *p++ = ' '; 
  194.         }
  195.         q = *arg;
  196.         numBackslashes = 0;
  197.         argNeedQuotes = 0;
  198.  
  199.         /* If the argument contains white space, it needs to be quoted. */
  200.         if (strpbrk(*arg, " \f\n\r\t\v")) {
  201.             argNeedQuotes = 1;
  202.         }
  203.  
  204.         if (argNeedQuotes) {
  205.             *p++ = '"';
  206.         }
  207.         while (*q) {
  208.             if (*q == '\\') {
  209.                 numBackslashes++;
  210.                 q++;
  211.             } else if (*q == '"') {
  212.                 if (numBackslashes) {
  213.                     /*
  214.                      * Double the backslashes since they are followed
  215.                      * by a quote
  216.                      */
  217.                     for (i = 0; i < 2 * numBackslashes; i++) {
  218.                         *p++ = '\\';
  219.                     }
  220.                     numBackslashes = 0;
  221.                 }
  222.                 /* To escape the quote */
  223.                 *p++ = '\\';
  224.                 *p++ = *q++;
  225.             } else {
  226.                 if (numBackslashes) {
  227.                     /*
  228.                      * Backslashes are not followed by a quote, so
  229.                      * don't need to double the backslashes.
  230.                      */
  231.                     for (i = 0; i < numBackslashes; i++) {
  232.                         *p++ = '\\';
  233.                     }
  234.                     numBackslashes = 0;
  235.                 }
  236.                 *p++ = *q++;
  237.             }
  238.         }
  239.  
  240.         /* Now we are at the end of this argument */
  241.         if (numBackslashes) {
  242.             /*
  243.              * Double the backslashes if we have a quote string
  244.              * delimiter at the end.
  245.              */
  246.             if (argNeedQuotes) {
  247.                 numBackslashes *= 2;
  248.             }
  249.             for (i = 0; i < numBackslashes; i++) {
  250.                 *p++ = '\\';
  251.             }
  252.         }
  253.         if (argNeedQuotes) {
  254.             *p++ = '"';
  255.         }
  256.     } 
  257.  
  258.     *p = '\0';
  259.     return 0;
  260. }
  261.  
  262. /*
  263.  * Assemble the environment block by concatenating the envp array
  264.  * (preserving the terminating null byte in each array element)
  265.  * and adding a null byte at the end.
  266.  *
  267.  * Returns 0 on success.  The resulting environment block is returned
  268.  * in *envBlock.  Note that if envp is NULL, a NULL pointer is returned
  269.  * in *envBlock.  Returns -1 on failure.
  270.  */
  271. static int assembleEnvBlock(char **envp, char **envBlock)
  272. {
  273.     char *p;
  274.     char *q;
  275.     char **env;
  276.     char *curEnv;
  277.     char *cwdStart, *cwdEnd;
  278.     int envBlockSize;
  279.  
  280.     if (envp == NULL) {
  281.         *envBlock = NULL;
  282.         return 0;
  283.     }
  284.  
  285.     curEnv = GetEnvironmentStrings();
  286.  
  287.     cwdStart = curEnv;
  288.     while (*cwdStart) {
  289.         if (cwdStart[0] == '=' && cwdStart[1] != '\0'
  290.                 && cwdStart[2] == ':' && cwdStart[3] == '=') {
  291.             break;
  292.         }
  293.         cwdStart += strlen(cwdStart) + 1;
  294.     }
  295.     cwdEnd = cwdStart;
  296.     if (*cwdEnd) {
  297.         cwdEnd += strlen(cwdEnd) + 1;
  298.         while (*cwdEnd) {
  299.             if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
  300.                     || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
  301.                 break;
  302.             }
  303.             cwdEnd += strlen(cwdEnd) + 1;
  304.         }
  305.     }
  306.     envBlockSize = cwdEnd - cwdStart;
  307.  
  308.     for (env = envp; *env; env++) {
  309.         envBlockSize += strlen(*env) + 1;
  310.     }
  311.     envBlockSize++;
  312.  
  313.     p = *envBlock = PR_MALLOC(envBlockSize);
  314.     if (p == NULL) {
  315.         FreeEnvironmentStrings(curEnv);
  316.         return -1;
  317.     }
  318.  
  319.     q = cwdStart;
  320.     while (q < cwdEnd) {
  321.         *p++ = *q++;
  322.     }
  323.     FreeEnvironmentStrings(curEnv);
  324.  
  325.     for (env = envp; *env; env++) {
  326.         q = *env;
  327.         while (*q) {
  328.             *p++ = *q++;
  329.         }
  330.         *p++ = '\0';
  331.     }
  332.     *p = '\0';
  333.     return 0;
  334. }
  335.  
  336. /*
  337.  * For qsort.  We sort (case-insensitive) the environment strings
  338.  * before generating the environment block.
  339.  */
  340. static int compare(const void *arg1, const void *arg2)
  341. {
  342.     return _stricmp(* (char**)arg1, * (char**)arg2);
  343. }
  344.  
  345. PRProcess * _PR_CreateWindowsProcess(
  346.     const char *path,
  347.     char *const *argv,
  348.     char *const *envp,
  349.     const PRProcessAttr *attr)
  350. {
  351.     STARTUPINFO startupInfo;
  352.     PROCESS_INFORMATION procInfo;
  353.     BOOL retVal;
  354.     char *cmdLine = NULL;
  355.     char *envBlock = NULL;
  356.     char **newEnvp;
  357.     PRProcess *proc = NULL;
  358.  
  359.     proc = PR_NEW(PRProcess);
  360.     if (!proc) {
  361.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  362.         goto errorExit;
  363.     }
  364.  
  365.     if (assembleCmdLine(argv, &cmdLine) == -1) {
  366.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  367.         goto errorExit;
  368.     }
  369.  
  370.     if (envp == NULL) {
  371.         newEnvp = NULL;
  372.     } else {
  373.         int i;
  374.         int numEnv = 0;
  375.         while (envp[numEnv]) {
  376.             numEnv++;
  377.         }
  378.         newEnvp = (char **) PR_MALLOC((numEnv+1) * sizeof(char *));
  379.         for (i = 0; i <= numEnv; i++) {
  380.             newEnvp[i] = envp[i];
  381.         }
  382.         qsort((void *) newEnvp, (size_t) numEnv, sizeof(char *), compare);
  383.     }
  384.     if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
  385.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  386.         goto errorExit;
  387.     }
  388.  
  389.     ZeroMemory(&startupInfo, sizeof(startupInfo));
  390.     startupInfo.cb = sizeof(startupInfo);
  391.  
  392.     if (attr) {
  393.         PRBool redirected = PR_FALSE;
  394.  
  395.         /*
  396.          * XXX the default value for stdin, stdout, and stderr
  397.          * should probably be the console input and output, not
  398.          * those of the parent process.
  399.          */
  400.         startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  401.         startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  402.         startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
  403.         if (attr->stdinFd) {
  404.             startupInfo.hStdInput = (HANDLE) attr->stdinFd->secret->md.osfd;
  405.             redirected = PR_TRUE;
  406.         }
  407.         if (attr->stdoutFd) {
  408.             startupInfo.hStdOutput = (HANDLE) attr->stdoutFd->secret->md.osfd;
  409.             redirected = PR_TRUE;
  410.         }
  411.         if (attr->stderrFd) {
  412.             startupInfo.hStdError = (HANDLE) attr->stderrFd->secret->md.osfd;
  413.             redirected = PR_TRUE;
  414.         }
  415.         if (redirected) {
  416.             startupInfo.dwFlags |= STARTF_USESTDHANDLES;
  417.         }
  418.     }
  419.  
  420.     retVal = CreateProcess(NULL,
  421.                            cmdLine,
  422.                            NULL,  /* security attributes for the new
  423.                                    * process */
  424.                            NULL,  /* security attributes for the primary
  425.                                    * thread in the new process */
  426.                            TRUE,  /* inherit handles */
  427.                            0,     /* creation flags */
  428.                            envBlock,  /* an environment block, consisting
  429.                                        * of a null-terminated block of
  430.                                        * null-terminated strings.  Each
  431.                                        * string is in the form:
  432.                                        *     name=value
  433.                                        * XXX: usually NULL */
  434.                            NULL,  /* current drive and directory */
  435.                            &startupInfo,
  436.                            &procInfo
  437.                           );
  438.     if (retVal == FALSE) {
  439.         /* XXX what error code? */
  440.         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
  441.         goto errorExit;
  442.     }
  443.  
  444.     CloseHandle(procInfo.hThread);
  445.     proc->md.handle = procInfo.hProcess;
  446.     proc->md.id = procInfo.dwProcessId;
  447.  
  448.     PR_DELETE(cmdLine);
  449.     if (envBlock) {
  450.         PR_DELETE(envBlock);
  451.     }
  452.     return proc;
  453.  
  454. errorExit:
  455.     if (cmdLine) {
  456.         PR_DELETE(cmdLine);
  457.     }
  458.     if (envBlock) {
  459.         PR_DELETE(envBlock);
  460.     }
  461.     if (proc) {
  462.         PR_DELETE(proc);
  463.     }
  464.     return NULL;
  465. }  /* _PR_CreateWindowsProcess */
  466.  
  467. PRStatus _PR_DetachWindowsProcess(PRProcess *process)
  468. {
  469.     CloseHandle(process->md.handle);
  470.     PR_DELETE(process);
  471.     return PR_SUCCESS;
  472. }
  473.  
  474. /*
  475.  * XXX: This implementation is a temporary quick solution.
  476.  * It can be called by native threads only (not by fibers).
  477.  */
  478. PRStatus _PR_WaitWindowsProcess(PRProcess *process,
  479.     PRInt32 *exitCode)
  480. {
  481.     DWORD dwRetVal;
  482.  
  483.     dwRetVal = WaitForSingleObject(process->md.handle, INFINITE);
  484.     if (dwRetVal == WAIT_FAILED) {
  485.         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
  486.         return PR_FAILURE;
  487.     }
  488.     PR_ASSERT(dwRetVal == WAIT_OBJECT_0);
  489.     if (exitCode != NULL &&
  490.             GetExitCodeProcess(process->md.handle, exitCode) == FALSE) {
  491.         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
  492.         return PR_FAILURE;
  493.     }
  494.     CloseHandle(process->md.handle);
  495.     PR_DELETE(process);
  496.     return PR_SUCCESS;
  497. }
  498.  
  499. PRStatus _PR_KillWindowsProcess(PRProcess *process)
  500. {
  501.     /*
  502.      * On Unix, if a process terminates normally, its exit code is
  503.      * between 0 and 255.  So here on Windows, we use the exit code
  504.      * 256 to indicate that the process is killed.
  505.      */
  506.     if (TerminateProcess(process->md.handle, 256)) {
  507.     return PR_SUCCESS;
  508.     }
  509.     PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
  510.     return PR_FAILURE;
  511. }
  512.  
  513. PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen)
  514. {
  515.     PRIntn rv;
  516.     PRInt32 syserror;
  517.  
  518.     rv = gethostname(name, (PRInt32) namelen);
  519.     if (0 == rv) {
  520.         return PR_SUCCESS;
  521.     }
  522.     syserror = WSAGetLastError();
  523.     PR_ASSERT(WSANOTINITIALISED != syserror);
  524.     _PR_MD_MAP_GETHOSTNAME_ERROR(syserror);
  525.     return PR_FAILURE;
  526. }
  527.  
  528. /*
  529.  **********************************************************************
  530.  *
  531.  * Memory-mapped files
  532.  *
  533.  **********************************************************************
  534.  */
  535.  
  536. PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
  537. {
  538.     DWORD dwHi, dwLo;
  539.     DWORD flProtect;
  540.  
  541.     dwLo = (DWORD) (size & 0xffffffff);
  542.     dwHi = (DWORD) (((PRUint64) size >> 32) & 0xffffffff);
  543.  
  544.     if (fmap->prot == PR_PROT_READONLY) {
  545.         flProtect = PAGE_READONLY;
  546.         fmap->md.dwAccess = FILE_MAP_READ;
  547.     } else if (fmap->prot == PR_PROT_READWRITE) {
  548.         flProtect = PAGE_READWRITE;
  549.         fmap->md.dwAccess = FILE_MAP_WRITE;
  550.     } else {
  551.         PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY);
  552.         flProtect = PAGE_WRITECOPY;
  553.         fmap->md.dwAccess = FILE_MAP_COPY;
  554.     }
  555.  
  556.     fmap->md.hFileMap = CreateFileMapping(
  557.         (HANDLE) fmap->fd->secret->md.osfd,
  558.         NULL,
  559.         flProtect,
  560.         dwHi,
  561.         dwLo,
  562.         NULL);
  563.  
  564.     if (fmap->md.hFileMap == NULL) {
  565.         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
  566.         return PR_FAILURE;
  567.     }
  568.     return PR_SUCCESS;
  569. }
  570.  
  571. void * _MD_MemMap(
  572.     PRFileMap *fmap,
  573.     PRInt64 offset,
  574.     PRUint32 len)
  575. {
  576.     DWORD dwHi, dwLo;
  577.     void *addr;
  578.  
  579.     dwLo = (DWORD) (offset & 0xffffffff);
  580.     dwHi = (DWORD) (((PRUint64) offset >> 32) & 0xffffffff);
  581.     if ((addr = MapViewOfFile(fmap->md.hFileMap, fmap->md.dwAccess,
  582.             dwHi, dwLo, len)) == NULL) {
  583.         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
  584.     }
  585.     return addr;
  586. }
  587.  
  588. PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
  589. {
  590.     if (UnmapViewOfFile(addr)) {
  591.         return PR_SUCCESS;
  592.     } else {
  593.         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
  594.         return PR_FAILURE;
  595.     }
  596. }
  597.  
  598. PRStatus _MD_CloseFileMap(PRFileMap *fmap)
  599. {
  600.     CloseHandle(fmap->md.hFileMap);
  601.     PR_DELETE(fmap);
  602.     return PR_SUCCESS;
  603. }
  604.