home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / windows / w95io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  22.9 KB  |  872 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. /* Windows 95 IO module
  20.  *
  21.  * Assumes synchronous I/O.
  22.  *
  23.  */
  24.  
  25. #include "primpl.h"
  26. #include <direct.h>
  27.  
  28. struct _MDLock               _pr_ioq_lock;
  29.  
  30. /*
  31.  * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
  32.  * We store the value in a PRTime variable for convenience.
  33.  * This constant is used by _PR_FileTimeToPRTime().
  34.  */
  35. static const PRTime _pr_filetime_offset = 116444736000000000i64;
  36.  
  37. void
  38. _PR_MD_INIT_IO()
  39. {
  40.     WORD WSAVersion = 0x0101;
  41.     WSADATA WSAData;
  42.  
  43.     WSAStartup(    WSAVersion, &WSAData );
  44.  
  45. #ifdef DEBUG
  46.     /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */
  47.     {
  48.         SYSTEMTIME systime;
  49.         union {
  50.            PRTime prt;
  51.            FILETIME ft;
  52.         } filetime;
  53.         BOOL rv;
  54.  
  55.         systime.wYear = 1970;
  56.         systime.wMonth = 1;
  57.         /* wDayOfWeek is ignored */
  58.         systime.wDay = 1;
  59.         systime.wHour = 0;
  60.         systime.wMinute = 0;
  61.         systime.wSecond = 0;
  62.         systime.wMilliseconds = 0;
  63.  
  64.         rv = SystemTimeToFileTime(&systime, &filetime.ft);
  65.         PR_ASSERT(0 != rv);
  66.         PR_ASSERT(filetime.prt == _pr_filetime_offset);
  67.     }
  68. #endif /* DEBUG */
  69. }
  70.  
  71. PRStatus
  72. _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
  73. {
  74.     DWORD rv;
  75.  
  76.     PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
  77.         INFINITE : PR_IntervalToMilliseconds(ticks);
  78.     rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
  79.     switch(rv) 
  80.     {
  81.         case WAIT_OBJECT_0:
  82.             return PR_SUCCESS;
  83.             break;
  84.         case WAIT_TIMEOUT:
  85.             _PR_THREAD_LOCK(thread);
  86.             if (thread->state == _PR_IO_WAIT) {
  87.               ;
  88.             } else {
  89.                 if (thread->wait.cvar != NULL) {
  90.                     thread->wait.cvar = NULL;
  91.                     _PR_THREAD_UNLOCK(thread);
  92.                 } else {
  93.                     /* The CVAR was notified just as the timeout
  94.                      * occurred.  This led to us being notified twice.
  95.                      * call WaitForSingleObject() to clear the semaphore.
  96.                      */
  97.                     _PR_THREAD_UNLOCK(thread);
  98.                     rv = WaitForSingleObject(thread->md.blocked_sema, 0);
  99.                     PR_ASSERT(rv == WAIT_OBJECT_0);
  100.                 }
  101.             }
  102.             return PR_SUCCESS;
  103.             break;
  104.         default:
  105.             return PR_FAILURE;
  106.             break;
  107.     }
  108. }
  109. PRStatus
  110. _PR_MD_WAKEUP_WAITER(PRThread *thread)
  111. {
  112.     if ( _PR_IS_NATIVE_THREAD(thread) ) 
  113.     {
  114.         if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE)
  115.             return PR_FAILURE;
  116.         else
  117.             return PR_SUCCESS;
  118.     }
  119. }
  120.  
  121.  
  122. /* --- FILE IO ----------------------------------------------------------- */
  123. /*
  124.  *  _PR_MD_OPEN() -- Open a file
  125.  *
  126.  *  returns: a fileHandle
  127.  *
  128.  *  The NSPR open flags (osflags) are translated into flags for Win95
  129.  *
  130.  *  Mode seems to be passed in as a unix style file permissions argument
  131.  *  as in 0666, in the case of opening the logFile. 
  132.  *
  133.  */
  134. PRInt32
  135. _PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
  136. {
  137.     HANDLE file;
  138.     PRInt32 access = 0;
  139.     PRInt32 flags = 0;
  140.     PRInt32 flag6 = 0;
  141.     
  142.     if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
  143.  
  144.     if (osflags & PR_RDONLY || osflags & PR_RDWR)
  145.         access |= GENERIC_READ;
  146.     if (osflags & PR_WRONLY || osflags & PR_RDWR)
  147.         access |= GENERIC_WRITE;
  148.     if (osflags & PR_CREATE_FILE)
  149.         flags = OPEN_ALWAYS;
  150.     else if (osflags & PR_TRUNCATE)
  151.         flags = CREATE_ALWAYS;
  152.     else
  153.         flags = OPEN_EXISTING;
  154.  
  155.     file = CreateFile(name,
  156.                       access,
  157.                       FILE_SHARE_READ|FILE_SHARE_WRITE,
  158.                       NULL,
  159.                       flags,
  160.                       flag6,
  161.                       NULL);
  162.     if (file == INVALID_HANDLE_VALUE) {
  163.         _PR_MD_MAP_OPEN_ERROR(GetLastError());
  164.         return -1; 
  165.     }
  166.  
  167.     return (PRInt32)file;
  168. }
  169.  
  170. PRInt32
  171. _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
  172. {
  173.     PRUint32 bytes;
  174.     int rv, err;
  175.  
  176.     rv = ReadFile((HANDLE)fd->secret->md.osfd,
  177.             (LPVOID)buf,
  178.             len,
  179.             &bytes,
  180.             NULL);
  181.     
  182.     if (rv == 0) 
  183.     {
  184.         err = GetLastError();
  185.         /* ERROR_HANDLE_EOF can only be returned by async io */
  186.         PR_ASSERT(err != ERROR_HANDLE_EOF);
  187.         if (err == ERROR_BROKEN_PIPE)
  188.             return 0;
  189.         else {
  190.             _PR_MD_MAP_READ_ERROR(err);
  191.         return -1;
  192.     }
  193.     }
  194.     return bytes;
  195. }
  196.  
  197. PRInt32
  198. _PR_MD_WRITE(PRFileDesc *fd, void *buf, PRInt32 len)
  199. {
  200.     PRInt32 f = fd->secret->md.osfd;
  201.     PRInt32 bytes;
  202.     int rv;
  203.     PRThread *me = _PR_MD_CURRENT_THREAD();
  204.     
  205.     rv = WriteFile((HANDLE)f,
  206.             buf,
  207.             len,
  208.             &bytes,
  209.             NULL );
  210.             
  211.     if (rv == 0) 
  212.     {
  213.         _PR_MD_MAP_WRITE_ERROR(GetLastError());
  214.         return -1;
  215.     }
  216.     return bytes;
  217. } /* --- end _PR_MD_WRITE() --- */
  218.  
  219. PRInt32
  220. _PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, int whence)
  221. {
  222.     PRInt32 rv;
  223.  
  224.     rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, 0, whence);
  225.  
  226.     /*
  227.      * If the lpDistanceToMoveHigh argument (third argument) is
  228.      * NULL, SetFilePointer returns 0xffffffff on failure.
  229.      */
  230.     if (-1 == rv) {
  231.         _PR_MD_MAP_LSEEK_ERROR(GetLastError());
  232.         return -1;
  233.     } else
  234.         return rv;
  235. }
  236.  
  237. PRInt64
  238. _PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, int whence)
  239. {
  240.     PRInt64 result;
  241.     PRInt32 rv, low = (PRInt32)offset, hi = (PRInt32)(offset >> 32);
  242.  
  243.     rv = SetFilePointer((HANDLE)fd->secret->md.osfd, low, &hi, whence);
  244.  
  245.     /*
  246.      * If the lpDistanceToMoveHigh argument (third argument) is
  247.      * NULL, SetFilePointer returns 0xffffffff on failure.
  248.      */
  249.     if (-1 == rv)
  250.     {
  251.         _PR_MD_MAP_LSEEK_ERROR(GetLastError());
  252.         return -1;
  253.     }
  254.  
  255.     result = (hi << 32) + rv;
  256.     return result;
  257. }
  258.  
  259. /*
  260.  * This is documented to succeed on read-only files, but Win32's
  261.  * FlushFileBuffers functions fails with "access denied" in such a
  262.  * case.  So we only signal an error if the error is *not* "access
  263.  * denied".
  264.  */
  265. PRInt32
  266. _PR_MD_FSYNC(PRFileDesc *fd)
  267. {
  268.     /*
  269.      * From the documentation:
  270.      *
  271.      *       On Windows NT, the function FlushFileBuffers fails if hFile
  272.      *       is a handle to console output. That is because console
  273.      *       output is not buffered. The function returns FALSE, and
  274.      *       GetLastError returns ERROR_INVALID_HANDLE.
  275.      *
  276.      * On the other hand, on Win95, it returns without error.  I cannot
  277.      * assume that 0, 1, and 2 are console, because if someone closes
  278.      * System.out and then opens a file, they might get file descriptor
  279.      * 1.  An error on *that* version of 1 should be reported, whereas
  280.      * an error on System.out (which was the original 1) should be
  281.      * ignored.  So I use isatty() to ensure that such an error was due
  282.      * to this bogosity, and if it was, I ignore the error.
  283.      */
  284.  
  285.     long handle = _get_osfhandle(fd->secret->md.osfd);
  286.     BOOL ok = FlushFileBuffers((HANDLE)handle);
  287.  
  288.     if (!ok) {
  289.     DWORD err = GetLastError();
  290.     if (err != ERROR_ACCESS_DENIED) {    // from winerror.h
  291.             _PR_MD_MAP_FSYNC_ERROR(err);
  292.         return -1;
  293.     }
  294.     }
  295.     return 0;
  296. }
  297.  
  298. PRInt32
  299. _MD_CloseFile(PRInt32 osfd)
  300. {
  301.     PRInt32 rv;
  302.     
  303.     rv = (CloseHandle((HANDLE)osfd))?0:-1;
  304.     if (rv == -1)
  305.         _PR_MD_MAP_CLOSE_ERROR(GetLastError());
  306.     return rv;
  307. }
  308.  
  309.  
  310. /* --- DIR IO ------------------------------------------------------------ */
  311. #define GetFileFromDIR(d)       (d)->d_entry.cFileName
  312. #define FileIsHidden(d)    ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
  313.  
  314. void FlipSlashes(char *cp, int len)
  315. {
  316.     while (--len >= 0) {
  317.     if (cp[0] == '/') {
  318.         cp[0] = PR_DIRECTORY_SEPARATOR;
  319.     }
  320.     cp++;
  321.     }
  322. }
  323.  
  324. /*
  325. **
  326. ** Local implementations of standard Unix RTL functions which are not provided
  327. ** by the VC RTL.
  328. **
  329. */
  330.  
  331. PRStatus
  332. _PR_MD_CLOSE_DIR(_MDDir *d)
  333. {
  334.     if ( d ) {
  335.         if (FindClose(d->d_hdl)) {
  336.         d->magic = (PRUint32)-1;
  337.         return PR_SUCCESS;
  338.         } else {
  339.             _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
  340.             return PR_FAILURE;
  341.         }
  342.     }
  343.     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  344.     return PR_FAILURE;
  345. }
  346.  
  347.  
  348. PRStatus
  349. _PR_MD_OPEN_DIR(_MDDir *d, const char *name)
  350. {
  351.     char filename[ MAX_PATH ];
  352.  
  353.     PR_snprintf(filename, MAX_PATH, "%s%s%s",
  354.                 name, PR_DIRECTORY_SEPARATOR_STR, "*.*");
  355.     FlipSlashes( filename, strlen(filename) );
  356.  
  357.     d->d_hdl = FindFirstFile( filename, &(d->d_entry) );
  358.     if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
  359.         _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
  360.         return PR_FAILURE;
  361.     }
  362.     d->firstEntry = PR_TRUE;
  363.     d->magic = _MD_MAGIC_DIR;
  364.     return PR_SUCCESS;
  365. }
  366.  
  367. char *
  368. _PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
  369. {
  370.     PRInt32 err;
  371.     BOOL rv;
  372.     char *fileName;
  373.  
  374.     if ( d ) {
  375.         while (1) {
  376.             if (d->firstEntry) {
  377.                 d->firstEntry = PR_FALSE;
  378.                 rv = 1;
  379.             } else {
  380.                 rv = FindNextFile(d->d_hdl, &(d->d_entry));
  381.             }
  382.             if (rv == 0) {
  383.                 break;
  384.             }
  385.             fileName = GetFileFromDIR(d);
  386.             if ( (flags & PR_SKIP_DOT) &&
  387.                  (fileName[0] == '.') && (fileName[1] == '\0'))
  388.                  continue;
  389.             if ( (flags & PR_SKIP_DOT_DOT) &&
  390.                  (fileName[0] == '.') && (fileName[1] == '.') &&
  391.                  (fileName[2] == '\0'))
  392.                  continue;
  393.             if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
  394.                  continue;
  395.             return fileName;
  396.         }
  397.         err = GetLastError();
  398.         PR_ASSERT(NO_ERROR != err);
  399.             _PR_MD_MAP_READDIR_ERROR(err);
  400.         return NULL;
  401.         }
  402.     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  403.     return NULL;
  404. }
  405.  
  406. PRInt32
  407. _PR_MD_DELETE(const char *name)
  408. {
  409.     if (DeleteFile(name)) {
  410.         return 0;
  411.     } else {
  412.         _PR_MD_MAP_DELETE_ERROR(GetLastError());
  413.         return -1;
  414.     }
  415. }
  416.  
  417. static void
  418. _PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm)
  419. {
  420.     PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
  421.     CopyMemory(prtm, filetime, sizeof(PRTime));
  422.     *prtm = (*prtm - _pr_filetime_offset) / 10i64;
  423.  
  424. #ifdef DEBUG
  425.     /* Doublecheck our calculation. */
  426.     {
  427.         SYSTEMTIME systime;
  428.         PRExplodedTime etm;
  429.         PRTime cmp; /* for comparison */
  430.         BOOL rv;
  431.  
  432.         rv = FileTimeToSystemTime(filetime, &systime);
  433.         PR_ASSERT(0 != rv);
  434.  
  435.         /*
  436.          * PR_ImplodeTime ignores wday and yday.
  437.          */
  438.         etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC;
  439.         etm.tm_sec = systime.wSecond;
  440.         etm.tm_min = systime.wMinute;
  441.         etm.tm_hour = systime.wHour;
  442.         etm.tm_mday = systime.wDay;
  443.         etm.tm_month = systime.wMonth - 1;
  444.         etm.tm_year = systime.wYear;
  445.         /*
  446.          * It is not well-documented what time zone the FILETIME's
  447.          * are in.  WIN32_FIND_DATA is documented to be in UTC (GMT).
  448.          * But BY_HANDLE_FILE_INFORMATION is unclear about this.
  449.          * By our best judgement, we assume that FILETIME is in UTC.
  450.          */
  451.         etm.tm_params.tp_gmt_offset = 0;
  452.         etm.tm_params.tp_dst_offset = 0;
  453.         cmp = PR_ImplodeTime(&etm);
  454.  
  455.         /*
  456.          * SYSTEMTIME is in milliseconds precision, so we convert PRTime's
  457.          * microseconds to milliseconds before doing the comparison.
  458.          */
  459.         PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC));
  460.     }
  461. #endif /* DEBUG */
  462. }
  463.  
  464. PRInt32
  465. _PR_MD_STAT(const char *fn, struct stat *info)
  466. {
  467.     PRInt32 rv;
  468.  
  469.     rv = _stat(fn, (struct _stat *)info);
  470.     if (-1 == rv) {
  471.         /*
  472.          * Check for MSVC runtime library _stat() bug.
  473.          * (It's really a bug in FindFirstFile().)
  474.          * If a pathname ends in a backslash or slash,
  475.          * e.g., c:\temp\ or c:/temp/, _stat() will fail.
  476.          * Note: a pathname ending in a slash (e.g., c:/temp/)
  477.          * can be handled by _stat() on NT but not on Win95.
  478.          *
  479.          * We remove the backslash or slash at the end and
  480.          * try again.
  481.          */
  482.  
  483.         int len = strlen(fn);
  484.         if (len > 0 && len <= _MAX_PATH
  485.                 && (fn[len - 1] == '\\' || fn[len - 1] == '/')) {
  486.             char newfn[_MAX_PATH + 1];
  487.  
  488.             strcpy(newfn, fn);
  489.             newfn[len - 1] = '\0';
  490.             rv = _stat(newfn, (struct _stat *)info);
  491.         }
  492.     }
  493.  
  494.     if (-1 == rv) {
  495.         _PR_MD_MAP_STAT_ERROR(errno);
  496.     }
  497.     return rv;
  498. }
  499.  
  500. #define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\')
  501.  
  502. /*
  503.  * IsRootDirectory --
  504.  *
  505.  * Return PR_TRUE if the pathname 'fn' is a valid root directory,
  506.  * else return PR_FALSE.  The char buffer pointed to by 'fn' must
  507.  * be writable.  During the execution of this function, the contents
  508.  * of the buffer pointed to by 'fn' may be modified, but on return
  509.  * the original contents will be restored.  'buflen' is the size of
  510.  * the buffer pointed to by 'fn'.
  511.  *
  512.  * Root directories come in three formats:
  513.  * 1. / or \, meaning the root directory of the current drive.
  514.  * 2. C:/ or C:\, where C is a drive letter.
  515.  * 3. \\<server name>\<share point name>\ or
  516.  *    \\<server name>\<share point name>, meaning the root directory
  517.  *    of a UNC (Universal Naming Convention) name.
  518.  */
  519.  
  520. static PRBool
  521. IsRootDirectory(char *fn, size_t buflen)
  522. {
  523.     char *p;
  524.     PRBool slashAdded = PR_FALSE;
  525.     PRBool rv = PR_FALSE;
  526.  
  527.     if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') {
  528.         return PR_TRUE;
  529.     }
  530.  
  531.     if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2])
  532.             && fn[3] == '\0') {
  533.         rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
  534.         return rv;
  535.     }
  536.  
  537.     /* The UNC root directory */
  538.  
  539.     if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) {
  540.         /* The 'server' part should have at least one character. */
  541.         p = &fn[2];
  542.         if (*p == '\0' || _PR_IS_SLASH(*p)) {
  543.             return PR_FALSE;
  544.         }
  545.  
  546.         /* look for the next slash */
  547.         do {
  548.             p++;
  549.         } while (*p != '\0' && !_PR_IS_SLASH(*p));
  550.         if (*p == '\0') {
  551.             return PR_FALSE;
  552.         }
  553.  
  554.         /* The 'share' part should have at least one character. */
  555.         p++;
  556.         if (*p == '\0' || _PR_IS_SLASH(*p)) {
  557.             return PR_FALSE;
  558.         }
  559.  
  560.         /* look for the final slash */
  561.         do {
  562.             p++;
  563.         } while (*p != '\0' && !_PR_IS_SLASH(*p));
  564.         if (_PR_IS_SLASH(*p) && p[1] != '\0') {
  565.             return PR_FALSE;
  566.         }
  567.         if (*p == '\0') {
  568.             /*
  569.              * GetDriveType() doesn't work correctly if the
  570.              * path is of the form \\server\share, so we add
  571.              * a final slash temporarily.
  572.              */
  573.             if ((p + 1) < (fn + buflen)) {
  574.                 *p++ = '\\';
  575.                 *p = '\0';
  576.                 slashAdded = PR_TRUE;
  577.             } else {
  578.                 return PR_FALSE; /* name too long */
  579.             }
  580.         }
  581.         rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
  582.         /* restore the 'fn' buffer */
  583.         if (slashAdded) {
  584.             *--p = '\0';
  585.         }
  586.     }
  587.     return rv;
  588. }
  589.  
  590. PRInt32
  591. _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
  592. {
  593.     HANDLE hFindFile;
  594.     WIN32_FIND_DATA findFileData;
  595.     char pathbuf[MAX_PATH + 1];
  596.     
  597.     if (NULL == fn || '\0' == *fn) {
  598.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  599.         return -1;
  600.     }
  601.  
  602.     /*
  603.      * FindFirstFile() expands wildcard characters.  So
  604.      * we make sure the pathname contains no wildcard.
  605.      */
  606.     if (NULL != strpbrk(fn, "?*")) {
  607.         PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0);
  608.         return -1;
  609.     }
  610.  
  611.     hFindFile = FindFirstFile(fn, &findFileData);
  612.     if (INVALID_HANDLE_VALUE == hFindFile) {
  613.         DWORD len;
  614.         char *filePart;
  615.  
  616.         /*
  617.          * FindFirstFile() does not work correctly on root directories.
  618.          * It also doesn't work correctly on a pathname that ends in a
  619.          * slash.  So we first check to see if the pathname specifies a
  620.          * root directory.  If not, and if the pathname ends in a slash,
  621.          * we remove the final slash and try again.
  622.          */
  623.  
  624.         /*
  625.          * If the pathname does not contain ., \, and /, it cannot be
  626.          * a root directory or a pathname that ends in a slash.
  627.          */
  628.         if (NULL == strpbrk(fn, ".\\/")) {
  629.             _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
  630.             return -1;
  631.         } 
  632.         len = GetFullPathName(fn, sizeof(pathbuf), pathbuf,
  633.                 &filePart);
  634.         PR_ASSERT(0 != len);
  635.         if (len > sizeof(pathbuf)) {
  636.             PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
  637.             return -1;
  638.         }
  639.         if (IsRootDirectory(pathbuf, sizeof(pathbuf))) {
  640.             info->type = PR_FILE_DIRECTORY;
  641.             info->size = 0;
  642.             /*
  643.              * These timestamps don't make sense for root directories.
  644.              */
  645.             info->modifyTime = 0;
  646.             info->creationTime = 0;
  647.             return 0;
  648.         }
  649.         if (!_PR_IS_SLASH(pathbuf[len - 1])) {
  650.             _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
  651.             return -1;
  652.         } else {
  653.             pathbuf[len - 1] = '\0';
  654.             hFindFile = FindFirstFile(pathbuf, &findFileData);
  655.             if (INVALID_HANDLE_VALUE == hFindFile) {
  656.                 _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
  657.                 return -1;
  658.             }
  659.         }
  660.     }
  661.  
  662.     FindClose(hFindFile);
  663.  
  664.     if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  665.         info->type = PR_FILE_DIRECTORY;
  666.     } else {
  667.         info->type = PR_FILE_FILE;
  668.     }
  669.  
  670.     info->size = findFileData.nFileSizeHigh;
  671.     info->size = (info->size << 32) + findFileData.nFileSizeLow;
  672.  
  673.     _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);
  674.  
  675.     if (0 == findFileData.ftCreationTime.dwLowDateTime &&
  676.             0 == findFileData.ftCreationTime.dwHighDateTime) {
  677.         info->creationTime = info->modifyTime;
  678.     } else {
  679.         _PR_FileTimeToPRTime(&findFileData.ftCreationTime,
  680.                 &info->creationTime);
  681.     }
  682.  
  683.     return 0;
  684. }
  685.  
  686. PRInt32
  687. _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
  688. {
  689.     PRFileInfo64 info64;
  690.     PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64);
  691.     if (0 == rv)
  692.     {
  693.         info->type = info64.type;
  694.         info->size = (PRUint32) info64.size;
  695.         info->modifyTime = info64.modifyTime;
  696.         info->creationTime = info64.creationTime;
  697.     }
  698.     return rv;
  699. }
  700.  
  701. PRInt32
  702. _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
  703. {
  704.     int rv;
  705.  
  706.     BY_HANDLE_FILE_INFORMATION hinfo;
  707.  
  708.     rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo);
  709.     if (rv == FALSE) {
  710.         _PR_MD_MAP_FSTAT_ERROR(GetLastError());
  711.         return -1;
  712.     }
  713.  
  714.     if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  715.         info->type = PR_FILE_DIRECTORY;
  716.     else
  717.         info->type = PR_FILE_FILE;
  718.  
  719.     info->size = hinfo.nFileSizeHigh;
  720.     info->size = (info->size << 32) + hinfo.nFileSizeLow;
  721.  
  722.     _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) );
  723.     _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) );
  724.  
  725.     return 0;
  726. }
  727.  
  728. PRInt32
  729. _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
  730. {
  731.     PRFileInfo64 info64;
  732.     int rv = _PR_MD_GETOPENFILEINFO64(fd, &info64);
  733.     if (0 == rv)
  734.     {
  735.         info->type = info64.type;
  736.         info->modifyTime = info64.modifyTime;
  737.         info->creationTime = info64.creationTime;
  738.         LL_L2I(info->size, info64.size);
  739.     }
  740.     return rv;
  741. }
  742.  
  743. PRInt32
  744. _PR_MD_RENAME(const char *from, const char *to)
  745. {
  746.     /* Does this work with dot-relative pathnames? */
  747.     if (MoveFile(from, to)) {
  748.         return 0;
  749.     } else {
  750.         _PR_MD_MAP_RENAME_ERROR(GetLastError());
  751.         return -1;
  752.     }
  753. }
  754.  
  755. PRInt32
  756. _PR_MD_ACCESS(const char *name, PRIntn how)
  757. {
  758. PRInt32 rv;
  759.     switch (how) {
  760.       case PR_ACCESS_WRITE_OK:
  761.         rv = _access(name, 02);
  762.         break;
  763.       case PR_ACCESS_READ_OK:
  764.         rv = _access(name, 04);
  765.         break;
  766.       case PR_ACCESS_EXISTS:
  767.         return _access(name, 00);
  768.           break;
  769.       default:
  770.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  771.         return -1;
  772.     }
  773.     if (rv < 0)
  774.         _PR_MD_MAP_ACCESS_ERROR(errno);
  775.     return rv;
  776. }
  777.  
  778. PRInt32
  779. _PR_MD_MKDIR(const char *name, PRIntn mode)
  780. {
  781.     /* XXXMB - how to translate the "mode"??? */
  782.     if (CreateDirectory(name, NULL)) {
  783.         return 0;
  784.     } else {
  785.         _PR_MD_MAP_MKDIR_ERROR(GetLastError());
  786.         return -1;
  787.     }
  788. }
  789.  
  790. PRInt32
  791. _PR_MD_RMDIR(const char *name)
  792. {
  793.     if (RemoveDirectory(name)) {
  794.         return 0;
  795.     } else {
  796.         _PR_MD_MAP_RMDIR_ERROR(GetLastError());
  797.         return -1;
  798.     }
  799. }
  800.  
  801. PRStatus
  802. _PR_MD_LOCKFILE(PRInt32 f)
  803. {
  804.     PRInt32   rv;
  805.  
  806.     /*
  807.      * loop trying to LockFile(),
  808.      * pause for a few miliseconds when can't get the lock
  809.      * and try again
  810.      */
  811.     for( rv = FALSE; rv == FALSE; /* do nothing */ )
  812.     {
  813.     
  814.         rv = LockFile( (HANDLE) f,
  815.             0l, 0l,
  816.             0x7fffffff, 0xffffffff ); 
  817.         if ( rv == FALSE )
  818.         {
  819.             DWORD rc = GetLastError();
  820.             Sleep( 50 );  // Sleep() a few milisecs and try again.
  821.         }            
  822.     } /* end for() */
  823.     return PR_SUCCESS;
  824. } /* end _PR_MD_LOCKFILE() */
  825.  
  826. PRStatus
  827. _PR_MD_TLOCKFILE(PRInt32 f)
  828. {
  829.     PRInt32   rv;
  830.     
  831.     /*
  832.      * loop trying to LockFile(),
  833.      * pause for a few miliseconds when can't get the lock
  834.      * and try again
  835.      */
  836.     for( rv = FALSE; rv == FALSE; /* do nothing */ )
  837.     {
  838.     
  839.         rv = LockFile( (HANDLE) f,
  840.             0l, 0l,
  841.             0x7fffffff, 0xffffffff ); 
  842.         if ( rv == FALSE )
  843.         {
  844.             DWORD rc = GetLastError();
  845.             Sleep( 50 );  // Sleep() a few milisecs and try again.
  846.         }            
  847.     } /* end for() */
  848.     return PR_SUCCESS;
  849. } /* end _PR_MD_TLOCKFILE() */
  850.  
  851.  
  852. PRStatus
  853. _PR_MD_UNLOCKFILE(PRInt32 f)
  854. {
  855.     PRInt32   rv;
  856.     
  857.     rv = UnlockFile( (HANDLE) f,
  858.             0l, 0l,
  859.             0x7fffffff, 0xffffffff ); 
  860.             
  861.     if ( rv )
  862.     {
  863.         return PR_SUCCESS;
  864.     }
  865.     else
  866.     {
  867.         int err = GetLastError();
  868.         return PR_FAILURE;
  869.     }
  870. } /* end _PR_MD_UNLOCKFILE() */
  871.  
  872.