| OLD | NEW | 
 | (Empty) | 
|     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |  | 
|     2 /* This Source Code Form is subject to the terms of the Mozilla Public |  | 
|     3  * License, v. 2.0. If a copy of the MPL was not distributed with this |  | 
|     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |  | 
|     5  |  | 
|     6 /* Windows 95 IO module |  | 
|     7  * |  | 
|     8  * Assumes synchronous I/O. |  | 
|     9  * |  | 
|    10  */ |  | 
|    11  |  | 
|    12 #include "primpl.h" |  | 
|    13 #include <direct.h> |  | 
|    14 #include <mbstring.h> |  | 
|    15 #ifdef MOZ_UNICODE |  | 
|    16 #include <wchar.h> |  | 
|    17 #endif /* MOZ_UNICODE */ |  | 
|    18  |  | 
|    19 struct _MDLock               _pr_ioq_lock; |  | 
|    20  |  | 
|    21 /* |  | 
|    22  * NSPR-to-NT access right mapping table for files. |  | 
|    23  */ |  | 
|    24 static DWORD fileAccessTable[] = { |  | 
|    25     FILE_GENERIC_READ, |  | 
|    26     FILE_GENERIC_WRITE, |  | 
|    27     FILE_GENERIC_EXECUTE |  | 
|    28 }; |  | 
|    29  |  | 
|    30 /* |  | 
|    31  * NSPR-to-NT access right mapping table for directories. |  | 
|    32  */ |  | 
|    33 static DWORD dirAccessTable[] = { |  | 
|    34     FILE_GENERIC_READ, |  | 
|    35     FILE_GENERIC_WRITE|FILE_DELETE_CHILD, |  | 
|    36     FILE_GENERIC_EXECUTE |  | 
|    37 }; |  | 
|    38  |  | 
|    39 static PRBool IsPrevCharSlash(const char *str, const char *current); |  | 
|    40  |  | 
|    41 void |  | 
|    42 _PR_MD_INIT_IO() |  | 
|    43 { |  | 
|    44     WORD WSAVersion = 0x0101; |  | 
|    45     WSADATA WSAData; |  | 
|    46     int err; |  | 
|    47  |  | 
|    48     err = WSAStartup( WSAVersion, &WSAData ); |  | 
|    49     PR_ASSERT(0 == err); |  | 
|    50  |  | 
|    51 #ifdef DEBUG |  | 
|    52     /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */ |  | 
|    53     { |  | 
|    54         SYSTEMTIME systime; |  | 
|    55         union { |  | 
|    56            PRTime prt; |  | 
|    57            FILETIME ft; |  | 
|    58         } filetime; |  | 
|    59         BOOL rv; |  | 
|    60  |  | 
|    61         systime.wYear = 1970; |  | 
|    62         systime.wMonth = 1; |  | 
|    63         /* wDayOfWeek is ignored */ |  | 
|    64         systime.wDay = 1; |  | 
|    65         systime.wHour = 0; |  | 
|    66         systime.wMinute = 0; |  | 
|    67         systime.wSecond = 0; |  | 
|    68         systime.wMilliseconds = 0; |  | 
|    69  |  | 
|    70         rv = SystemTimeToFileTime(&systime, &filetime.ft); |  | 
|    71         PR_ASSERT(0 != rv); |  | 
|    72         PR_ASSERT(filetime.prt == _pr_filetime_offset); |  | 
|    73     } |  | 
|    74 #endif /* DEBUG */ |  | 
|    75  |  | 
|    76     _PR_NT_InitSids(); |  | 
|    77  |  | 
|    78     _PR_MD_InitSockets(); |  | 
|    79 } |  | 
|    80  |  | 
|    81 PRStatus |  | 
|    82 _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) |  | 
|    83 { |  | 
|    84     DWORD rv; |  | 
|    85  |  | 
|    86     PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? |  | 
|    87         INFINITE : PR_IntervalToMilliseconds(ticks); |  | 
|    88     rv = WaitForSingleObject(thread->md.blocked_sema, msecs); |  | 
|    89     switch(rv)  |  | 
|    90     { |  | 
|    91         case WAIT_OBJECT_0: |  | 
|    92             return PR_SUCCESS; |  | 
|    93         case WAIT_TIMEOUT: |  | 
|    94             _PR_THREAD_LOCK(thread); |  | 
|    95             if (thread->state == _PR_IO_WAIT) { |  | 
|    96                           ; |  | 
|    97             } else { |  | 
|    98                 if (thread->wait.cvar != NULL) { |  | 
|    99                     thread->wait.cvar = NULL; |  | 
|   100                     _PR_THREAD_UNLOCK(thread); |  | 
|   101                 } else { |  | 
|   102                     /* The CVAR was notified just as the timeout |  | 
|   103                      * occurred.  This led to us being notified twice. |  | 
|   104                      * call WaitForSingleObject() to clear the semaphore. |  | 
|   105                      */ |  | 
|   106                     _PR_THREAD_UNLOCK(thread); |  | 
|   107                     rv = WaitForSingleObject(thread->md.blocked_sema, 0); |  | 
|   108                     PR_ASSERT(rv == WAIT_OBJECT_0); |  | 
|   109                 } |  | 
|   110             } |  | 
|   111             return PR_SUCCESS; |  | 
|   112         default: |  | 
|   113             return PR_FAILURE; |  | 
|   114     } |  | 
|   115 } |  | 
|   116 PRStatus |  | 
|   117 _PR_MD_WAKEUP_WAITER(PRThread *thread) |  | 
|   118 { |  | 
|   119     if ( _PR_IS_NATIVE_THREAD(thread) )  |  | 
|   120     { |  | 
|   121         if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE) |  | 
|   122             return PR_FAILURE; |  | 
|   123         else |  | 
|   124                         return PR_SUCCESS; |  | 
|   125         } |  | 
|   126 } |  | 
|   127  |  | 
|   128  |  | 
|   129 /* --- FILE IO ----------------------------------------------------------- */ |  | 
|   130 /* |  | 
|   131  *  _PR_MD_OPEN() -- Open a file |  | 
|   132  * |  | 
|   133  *  returns: a fileHandle |  | 
|   134  * |  | 
|   135  *  The NSPR open flags (osflags) are translated into flags for Win95 |  | 
|   136  * |  | 
|   137  *  Mode seems to be passed in as a unix style file permissions argument |  | 
|   138  *  as in 0666, in the case of opening the logFile.  |  | 
|   139  * |  | 
|   140  */ |  | 
|   141 PROsfd |  | 
|   142 _PR_MD_OPEN(const char *name, PRIntn osflags, int mode) |  | 
|   143 { |  | 
|   144     HANDLE file; |  | 
|   145     PRInt32 access = 0; |  | 
|   146     PRInt32 flags = 0; |  | 
|   147     PRInt32 flag6 = 0; |  | 
|   148      |  | 
|   149     if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; |  | 
|   150   |  | 
|   151     if (osflags & PR_RDONLY || osflags & PR_RDWR) |  | 
|   152         access |= GENERIC_READ; |  | 
|   153     if (osflags & PR_WRONLY || osflags & PR_RDWR) |  | 
|   154         access |= GENERIC_WRITE; |  | 
|   155  |  | 
|   156     if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) |  | 
|   157         flags = CREATE_NEW; |  | 
|   158     else if (osflags & PR_CREATE_FILE) { |  | 
|   159         if (osflags & PR_TRUNCATE) |  | 
|   160             flags = CREATE_ALWAYS; |  | 
|   161         else |  | 
|   162             flags = OPEN_ALWAYS; |  | 
|   163     } else { |  | 
|   164         if (osflags & PR_TRUNCATE) |  | 
|   165             flags = TRUNCATE_EXISTING; |  | 
|   166         else |  | 
|   167             flags = OPEN_EXISTING; |  | 
|   168     } |  | 
|   169  |  | 
|   170     file = CreateFileA(name, |  | 
|   171                        access, |  | 
|   172                        FILE_SHARE_READ|FILE_SHARE_WRITE, |  | 
|   173                        NULL, |  | 
|   174                        flags, |  | 
|   175                        flag6, |  | 
|   176                        NULL); |  | 
|   177     if (file == INVALID_HANDLE_VALUE) { |  | 
|   178                 _PR_MD_MAP_OPEN_ERROR(GetLastError()); |  | 
|   179         return -1;  |  | 
|   180         } |  | 
|   181  |  | 
|   182     return (PROsfd)file; |  | 
|   183 } |  | 
|   184  |  | 
|   185 PROsfd |  | 
|   186 _PR_MD_OPEN_FILE(const char *name, PRIntn osflags, int mode) |  | 
|   187 { |  | 
|   188     HANDLE file; |  | 
|   189     PRInt32 access = 0; |  | 
|   190     PRInt32 flags = 0; |  | 
|   191     PRInt32 flag6 = 0; |  | 
|   192     SECURITY_ATTRIBUTES sa; |  | 
|   193     LPSECURITY_ATTRIBUTES lpSA = NULL; |  | 
|   194     PSECURITY_DESCRIPTOR pSD = NULL; |  | 
|   195     PACL pACL = NULL; |  | 
|   196  |  | 
|   197     if (osflags & PR_CREATE_FILE) { |  | 
|   198         if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, |  | 
|   199                 &pSD, &pACL) == PR_SUCCESS) { |  | 
|   200             sa.nLength = sizeof(sa); |  | 
|   201             sa.lpSecurityDescriptor = pSD; |  | 
|   202             sa.bInheritHandle = FALSE; |  | 
|   203             lpSA = &sa; |  | 
|   204         } |  | 
|   205     } |  | 
|   206      |  | 
|   207     if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; |  | 
|   208   |  | 
|   209     if (osflags & PR_RDONLY || osflags & PR_RDWR) |  | 
|   210         access |= GENERIC_READ; |  | 
|   211     if (osflags & PR_WRONLY || osflags & PR_RDWR) |  | 
|   212         access |= GENERIC_WRITE; |  | 
|   213  |  | 
|   214     if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) |  | 
|   215         flags = CREATE_NEW; |  | 
|   216     else if (osflags & PR_CREATE_FILE) { |  | 
|   217         if (osflags & PR_TRUNCATE) |  | 
|   218             flags = CREATE_ALWAYS; |  | 
|   219         else |  | 
|   220             flags = OPEN_ALWAYS; |  | 
|   221     } else { |  | 
|   222         if (osflags & PR_TRUNCATE) |  | 
|   223             flags = TRUNCATE_EXISTING; |  | 
|   224         else |  | 
|   225             flags = OPEN_EXISTING; |  | 
|   226     } |  | 
|   227  |  | 
|   228     file = CreateFileA(name, |  | 
|   229                        access, |  | 
|   230                        FILE_SHARE_READ|FILE_SHARE_WRITE, |  | 
|   231                        lpSA, |  | 
|   232                        flags, |  | 
|   233                        flag6, |  | 
|   234                        NULL); |  | 
|   235     if (lpSA != NULL) { |  | 
|   236         _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); |  | 
|   237     } |  | 
|   238     if (file == INVALID_HANDLE_VALUE) { |  | 
|   239                 _PR_MD_MAP_OPEN_ERROR(GetLastError()); |  | 
|   240         return -1;  |  | 
|   241         } |  | 
|   242  |  | 
|   243     return (PROsfd)file; |  | 
|   244 } |  | 
|   245  |  | 
|   246 PRInt32 |  | 
|   247 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) |  | 
|   248 { |  | 
|   249     PRUint32 bytes; |  | 
|   250     int rv, err; |  | 
|   251  |  | 
|   252     rv = ReadFile((HANDLE)fd->secret->md.osfd, |  | 
|   253             (LPVOID)buf, |  | 
|   254             len, |  | 
|   255             &bytes, |  | 
|   256             NULL); |  | 
|   257      |  | 
|   258     if (rv == 0)  |  | 
|   259     { |  | 
|   260         err = GetLastError(); |  | 
|   261         /* ERROR_HANDLE_EOF can only be returned by async io */ |  | 
|   262         PR_ASSERT(err != ERROR_HANDLE_EOF); |  | 
|   263         if (err == ERROR_BROKEN_PIPE) |  | 
|   264             return 0; |  | 
|   265                 else { |  | 
|   266                         _PR_MD_MAP_READ_ERROR(err); |  | 
|   267         return -1; |  | 
|   268     } |  | 
|   269     } |  | 
|   270     return bytes; |  | 
|   271 } |  | 
|   272  |  | 
|   273 PRInt32 |  | 
|   274 _PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) |  | 
|   275 { |  | 
|   276     PROsfd f = fd->secret->md.osfd; |  | 
|   277     PRInt32 bytes; |  | 
|   278     int rv; |  | 
|   279      |  | 
|   280     rv = WriteFile((HANDLE)f, |  | 
|   281             buf, |  | 
|   282             len, |  | 
|   283             &bytes, |  | 
|   284             NULL ); |  | 
|   285              |  | 
|   286     if (rv == 0)  |  | 
|   287     { |  | 
|   288                 _PR_MD_MAP_WRITE_ERROR(GetLastError()); |  | 
|   289         return -1; |  | 
|   290     } |  | 
|   291     return bytes; |  | 
|   292 } /* --- end _PR_MD_WRITE() --- */ |  | 
|   293  |  | 
|   294 PROffset32 |  | 
|   295 _PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) |  | 
|   296 { |  | 
|   297     DWORD moveMethod; |  | 
|   298     PROffset32 rv; |  | 
|   299  |  | 
|   300     switch (whence) { |  | 
|   301         case PR_SEEK_SET: |  | 
|   302             moveMethod = FILE_BEGIN; |  | 
|   303             break; |  | 
|   304         case PR_SEEK_CUR: |  | 
|   305             moveMethod = FILE_CURRENT; |  | 
|   306             break; |  | 
|   307         case PR_SEEK_END: |  | 
|   308             moveMethod = FILE_END; |  | 
|   309             break; |  | 
|   310         default: |  | 
|   311             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |  | 
|   312             return -1; |  | 
|   313     } |  | 
|   314  |  | 
|   315     rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod); |  | 
|   316  |  | 
|   317     /* |  | 
|   318      * If the lpDistanceToMoveHigh argument (third argument) is |  | 
|   319      * NULL, SetFilePointer returns 0xffffffff on failure. |  | 
|   320      */ |  | 
|   321     if (-1 == rv) { |  | 
|   322         _PR_MD_MAP_LSEEK_ERROR(GetLastError()); |  | 
|   323     } |  | 
|   324     return rv; |  | 
|   325 } |  | 
|   326  |  | 
|   327 PROffset64 |  | 
|   328 _PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) |  | 
|   329 { |  | 
|   330     DWORD moveMethod; |  | 
|   331     LARGE_INTEGER li; |  | 
|   332     DWORD err; |  | 
|   333  |  | 
|   334     switch (whence) { |  | 
|   335         case PR_SEEK_SET: |  | 
|   336             moveMethod = FILE_BEGIN; |  | 
|   337             break; |  | 
|   338         case PR_SEEK_CUR: |  | 
|   339             moveMethod = FILE_CURRENT; |  | 
|   340             break; |  | 
|   341         case PR_SEEK_END: |  | 
|   342             moveMethod = FILE_END; |  | 
|   343             break; |  | 
|   344         default: |  | 
|   345             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |  | 
|   346             return -1; |  | 
|   347     } |  | 
|   348  |  | 
|   349     li.QuadPart = offset; |  | 
|   350     li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd, |  | 
|   351             li.LowPart, &li.HighPart, moveMethod); |  | 
|   352  |  | 
|   353     if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) { |  | 
|   354         _PR_MD_MAP_LSEEK_ERROR(err); |  | 
|   355         li.QuadPart = -1; |  | 
|   356     } |  | 
|   357     return li.QuadPart; |  | 
|   358 } |  | 
|   359  |  | 
|   360 /* |  | 
|   361  * This is documented to succeed on read-only files, but Win32's |  | 
|   362  * FlushFileBuffers functions fails with "access denied" in such a |  | 
|   363  * case.  So we only signal an error if the error is *not* "access |  | 
|   364  * denied". |  | 
|   365  */ |  | 
|   366 PRInt32 |  | 
|   367 _PR_MD_FSYNC(PRFileDesc *fd) |  | 
|   368 { |  | 
|   369     /* |  | 
|   370      * From the documentation: |  | 
|   371      * |  | 
|   372      *     On Windows NT, the function FlushFileBuffers fails if hFile |  | 
|   373      *     is a handle to console output. That is because console |  | 
|   374      *     output is not buffered. The function returns FALSE, and |  | 
|   375      *     GetLastError returns ERROR_INVALID_HANDLE. |  | 
|   376      * |  | 
|   377      * On the other hand, on Win95, it returns without error.  I cannot |  | 
|   378      * assume that 0, 1, and 2 are console, because if someone closes |  | 
|   379      * System.out and then opens a file, they might get file descriptor |  | 
|   380      * 1.  An error on *that* version of 1 should be reported, whereas |  | 
|   381      * an error on System.out (which was the original 1) should be |  | 
|   382      * ignored.  So I use isatty() to ensure that such an error was due |  | 
|   383      * to this bogosity, and if it was, I ignore the error. |  | 
|   384      */ |  | 
|   385  |  | 
|   386     BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd); |  | 
|   387  |  | 
|   388     if (!ok) { |  | 
|   389         DWORD err = GetLastError(); |  | 
|   390         if (err != ERROR_ACCESS_DENIED) {       // from winerror.h |  | 
|   391                         _PR_MD_MAP_FSYNC_ERROR(err); |  | 
|   392             return -1; |  | 
|   393         } |  | 
|   394     } |  | 
|   395     return 0; |  | 
|   396 } |  | 
|   397  |  | 
|   398 PRInt32 |  | 
|   399 _MD_CloseFile(PROsfd osfd) |  | 
|   400 { |  | 
|   401     PRInt32 rv; |  | 
|   402      |  | 
|   403     rv = (CloseHandle((HANDLE)osfd))?0:-1; |  | 
|   404         if (rv == -1) |  | 
|   405                 _PR_MD_MAP_CLOSE_ERROR(GetLastError()); |  | 
|   406     return rv; |  | 
|   407 } |  | 
|   408  |  | 
|   409  |  | 
|   410 /* --- DIR IO ------------------------------------------------------------ */ |  | 
|   411 #define GetFileFromDIR(d)       (d)->d_entry.cFileName |  | 
|   412 #define FileIsHidden(d) ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) |  | 
|   413  |  | 
|   414 static void FlipSlashes(char *cp, size_t len) |  | 
|   415 { |  | 
|   416     while (len-- > 0) { |  | 
|   417         if (cp[0] == '/') { |  | 
|   418             cp[0] = PR_DIRECTORY_SEPARATOR; |  | 
|   419         } |  | 
|   420         cp = _mbsinc(cp); |  | 
|   421     } |  | 
|   422 } /* end FlipSlashes() */ |  | 
|   423  |  | 
|   424  |  | 
|   425 /* |  | 
|   426 ** |  | 
|   427 ** Local implementations of standard Unix RTL functions which are not provided |  | 
|   428 ** by the VC RTL. |  | 
|   429 ** |  | 
|   430 */ |  | 
|   431  |  | 
|   432 PRInt32 |  | 
|   433 _PR_MD_CLOSE_DIR(_MDDir *d) |  | 
|   434 { |  | 
|   435     if ( d ) { |  | 
|   436         if (FindClose(d->d_hdl)) { |  | 
|   437         d->magic = (PRUint32)-1; |  | 
|   438         return 0; |  | 
|   439                 } else { |  | 
|   440                         _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); |  | 
|   441                 return -1; |  | 
|   442                 } |  | 
|   443     } |  | 
|   444     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |  | 
|   445     return -1; |  | 
|   446 } |  | 
|   447  |  | 
|   448  |  | 
|   449 PRStatus |  | 
|   450 _PR_MD_OPEN_DIR(_MDDir *d, const char *name) |  | 
|   451 { |  | 
|   452     char filename[ MAX_PATH ]; |  | 
|   453     size_t len; |  | 
|   454  |  | 
|   455     len = strlen(name); |  | 
|   456     /* Need 5 bytes for \*.* and the trailing null byte. */ |  | 
|   457     if (len + 5 > MAX_PATH) { |  | 
|   458         PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); |  | 
|   459         return PR_FAILURE; |  | 
|   460     } |  | 
|   461     strcpy(filename, name); |  | 
|   462  |  | 
|   463     /* |  | 
|   464      * If 'name' ends in a slash or backslash, do not append |  | 
|   465      * another backslash. |  | 
|   466      */ |  | 
|   467     if (IsPrevCharSlash(filename, filename + len)) { |  | 
|   468         len--; |  | 
|   469     } |  | 
|   470     strcpy(&filename[len], "\\*.*"); |  | 
|   471     FlipSlashes( filename, strlen(filename) ); |  | 
|   472  |  | 
|   473     d->d_hdl = FindFirstFileA( filename, &(d->d_entry) ); |  | 
|   474     if ( d->d_hdl == INVALID_HANDLE_VALUE ) { |  | 
|   475                 _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); |  | 
|   476         return PR_FAILURE; |  | 
|   477     } |  | 
|   478     d->firstEntry = PR_TRUE; |  | 
|   479     d->magic = _MD_MAGIC_DIR; |  | 
|   480     return PR_SUCCESS; |  | 
|   481 } |  | 
|   482  |  | 
|   483 char * |  | 
|   484 _PR_MD_READ_DIR(_MDDir *d, PRIntn flags) |  | 
|   485 { |  | 
|   486     PRInt32 err; |  | 
|   487     BOOL rv; |  | 
|   488     char *fileName; |  | 
|   489  |  | 
|   490     if ( d ) { |  | 
|   491         while (1) { |  | 
|   492             if (d->firstEntry) { |  | 
|   493                 d->firstEntry = PR_FALSE; |  | 
|   494                 rv = 1; |  | 
|   495             } else { |  | 
|   496                 rv = FindNextFileA(d->d_hdl, &(d->d_entry)); |  | 
|   497             } |  | 
|   498             if (rv == 0) { |  | 
|   499                 break; |  | 
|   500             } |  | 
|   501             fileName = GetFileFromDIR(d); |  | 
|   502             if ( (flags & PR_SKIP_DOT) && |  | 
|   503                  (fileName[0] == '.') && (fileName[1] == '\0')) |  | 
|   504                  continue; |  | 
|   505             if ( (flags & PR_SKIP_DOT_DOT) && |  | 
|   506                  (fileName[0] == '.') && (fileName[1] == '.') && |  | 
|   507                  (fileName[2] == '\0')) |  | 
|   508                  continue; |  | 
|   509             if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) |  | 
|   510                  continue; |  | 
|   511             return fileName; |  | 
|   512         } |  | 
|   513         err = GetLastError(); |  | 
|   514         PR_ASSERT(NO_ERROR != err); |  | 
|   515                         _PR_MD_MAP_READDIR_ERROR(err); |  | 
|   516         return NULL; |  | 
|   517                 } |  | 
|   518     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |  | 
|   519     return NULL; |  | 
|   520 } |  | 
|   521  |  | 
|   522 PRInt32 |  | 
|   523 _PR_MD_DELETE(const char *name) |  | 
|   524 { |  | 
|   525     if (DeleteFileA(name)) { |  | 
|   526         return 0; |  | 
|   527     } else { |  | 
|   528                 _PR_MD_MAP_DELETE_ERROR(GetLastError()); |  | 
|   529         return -1; |  | 
|   530     } |  | 
|   531 } |  | 
|   532  |  | 
|   533 void |  | 
|   534 _PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm) |  | 
|   535 { |  | 
|   536     PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime)); |  | 
|   537     CopyMemory(prtm, filetime, sizeof(PRTime)); |  | 
|   538 #if defined(__MINGW32__) |  | 
|   539     *prtm = (*prtm - _pr_filetime_offset) / 10LL; |  | 
|   540 #else |  | 
|   541     *prtm = (*prtm - _pr_filetime_offset) / 10i64; |  | 
|   542 #endif |  | 
|   543  |  | 
|   544 #ifdef DEBUG |  | 
|   545     /* Doublecheck our calculation. */ |  | 
|   546     { |  | 
|   547         SYSTEMTIME systime; |  | 
|   548         PRExplodedTime etm; |  | 
|   549         PRTime cmp; /* for comparison */ |  | 
|   550         BOOL rv; |  | 
|   551  |  | 
|   552         rv = FileTimeToSystemTime(filetime, &systime); |  | 
|   553         PR_ASSERT(0 != rv); |  | 
|   554  |  | 
|   555         /* |  | 
|   556          * PR_ImplodeTime ignores wday and yday. |  | 
|   557          */ |  | 
|   558         etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC; |  | 
|   559         etm.tm_sec = systime.wSecond; |  | 
|   560         etm.tm_min = systime.wMinute; |  | 
|   561         etm.tm_hour = systime.wHour; |  | 
|   562         etm.tm_mday = systime.wDay; |  | 
|   563         etm.tm_month = systime.wMonth - 1; |  | 
|   564         etm.tm_year = systime.wYear; |  | 
|   565         /* |  | 
|   566          * It is not well-documented what time zone the FILETIME's |  | 
|   567          * are in.  WIN32_FIND_DATA is documented to be in UTC (GMT). |  | 
|   568          * But BY_HANDLE_FILE_INFORMATION is unclear about this. |  | 
|   569          * By our best judgement, we assume that FILETIME is in UTC. |  | 
|   570          */ |  | 
|   571         etm.tm_params.tp_gmt_offset = 0; |  | 
|   572         etm.tm_params.tp_dst_offset = 0; |  | 
|   573         cmp = PR_ImplodeTime(&etm); |  | 
|   574  |  | 
|   575         /* |  | 
|   576          * SYSTEMTIME is in milliseconds precision, so we convert PRTime's |  | 
|   577          * microseconds to milliseconds before doing the comparison. |  | 
|   578          */ |  | 
|   579         PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC)); |  | 
|   580     } |  | 
|   581 #endif /* DEBUG */ |  | 
|   582 } |  | 
|   583  |  | 
|   584 PRInt32 |  | 
|   585 _PR_MD_STAT(const char *fn, struct stat *info) |  | 
|   586 { |  | 
|   587     PRInt32 rv; |  | 
|   588  |  | 
|   589     rv = _stat(fn, (struct _stat *)info); |  | 
|   590     if (-1 == rv) { |  | 
|   591         /* |  | 
|   592          * Check for MSVC runtime library _stat() bug. |  | 
|   593          * (It's really a bug in FindFirstFile().) |  | 
|   594          * If a pathname ends in a backslash or slash, |  | 
|   595          * e.g., c:\temp\ or c:/temp/, _stat() will fail. |  | 
|   596          * Note: a pathname ending in a slash (e.g., c:/temp/) |  | 
|   597          * can be handled by _stat() on NT but not on Win95. |  | 
|   598          * |  | 
|   599          * We remove the backslash or slash at the end and |  | 
|   600          * try again. |  | 
|   601          */ |  | 
|   602  |  | 
|   603         size_t len = strlen(fn); |  | 
|   604         if (len > 0 && len <= _MAX_PATH |  | 
|   605                 && IsPrevCharSlash(fn, fn + len)) { |  | 
|   606             char newfn[_MAX_PATH + 1]; |  | 
|   607  |  | 
|   608             strcpy(newfn, fn); |  | 
|   609             newfn[len - 1] = '\0'; |  | 
|   610             rv = _stat(newfn, (struct _stat *)info); |  | 
|   611         } |  | 
|   612     } |  | 
|   613  |  | 
|   614     if (-1 == rv) { |  | 
|   615         _PR_MD_MAP_STAT_ERROR(errno); |  | 
|   616     } |  | 
|   617     return rv; |  | 
|   618 } |  | 
|   619  |  | 
|   620 #define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\') |  | 
|   621  |  | 
|   622 static PRBool |  | 
|   623 IsPrevCharSlash(const char *str, const char *current) |  | 
|   624 { |  | 
|   625     const char *prev; |  | 
|   626  |  | 
|   627     if (str >= current) |  | 
|   628         return PR_FALSE; |  | 
|   629     prev = _mbsdec(str, current); |  | 
|   630     return (prev == current - 1) && _PR_IS_SLASH(*prev); |  | 
|   631 } |  | 
|   632  |  | 
|   633 /* |  | 
|   634  * IsRootDirectory -- |  | 
|   635  * |  | 
|   636  * Return PR_TRUE if the pathname 'fn' is a valid root directory, |  | 
|   637  * else return PR_FALSE.  The char buffer pointed to by 'fn' must |  | 
|   638  * be writable.  During the execution of this function, the contents |  | 
|   639  * of the buffer pointed to by 'fn' may be modified, but on return |  | 
|   640  * the original contents will be restored.  'buflen' is the size of |  | 
|   641  * the buffer pointed to by 'fn'. |  | 
|   642  * |  | 
|   643  * Root directories come in three formats: |  | 
|   644  * 1. / or \, meaning the root directory of the current drive. |  | 
|   645  * 2. C:/ or C:\, where C is a drive letter. |  | 
|   646  * 3. \\<server name>\<share point name>\ or |  | 
|   647  *    \\<server name>\<share point name>, meaning the root directory |  | 
|   648  *    of a UNC (Universal Naming Convention) name. |  | 
|   649  */ |  | 
|   650  |  | 
|   651 static PRBool |  | 
|   652 IsRootDirectory(char *fn, size_t buflen) |  | 
|   653 { |  | 
|   654     char *p; |  | 
|   655     PRBool slashAdded = PR_FALSE; |  | 
|   656     PRBool rv = PR_FALSE; |  | 
|   657  |  | 
|   658     if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') { |  | 
|   659         return PR_TRUE; |  | 
|   660     } |  | 
|   661  |  | 
|   662     if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2]) |  | 
|   663             && fn[3] == '\0') { |  | 
|   664         rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; |  | 
|   665         return rv; |  | 
|   666     } |  | 
|   667  |  | 
|   668     /* The UNC root directory */ |  | 
|   669  |  | 
|   670     if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) { |  | 
|   671         /* The 'server' part should have at least one character. */ |  | 
|   672         p = &fn[2]; |  | 
|   673         if (*p == '\0' || _PR_IS_SLASH(*p)) { |  | 
|   674             return PR_FALSE; |  | 
|   675         } |  | 
|   676  |  | 
|   677         /* look for the next slash */ |  | 
|   678         do { |  | 
|   679             p = _mbsinc(p); |  | 
|   680         } while (*p != '\0' && !_PR_IS_SLASH(*p)); |  | 
|   681         if (*p == '\0') { |  | 
|   682             return PR_FALSE; |  | 
|   683         } |  | 
|   684  |  | 
|   685         /* The 'share' part should have at least one character. */ |  | 
|   686         p++; |  | 
|   687         if (*p == '\0' || _PR_IS_SLASH(*p)) { |  | 
|   688             return PR_FALSE; |  | 
|   689         } |  | 
|   690  |  | 
|   691         /* look for the final slash */ |  | 
|   692         do { |  | 
|   693             p = _mbsinc(p); |  | 
|   694         } while (*p != '\0' && !_PR_IS_SLASH(*p)); |  | 
|   695         if (_PR_IS_SLASH(*p) && p[1] != '\0') { |  | 
|   696             return PR_FALSE; |  | 
|   697         } |  | 
|   698         if (*p == '\0') { |  | 
|   699             /* |  | 
|   700              * GetDriveType() doesn't work correctly if the |  | 
|   701              * path is of the form \\server\share, so we add |  | 
|   702              * a final slash temporarily. |  | 
|   703              */ |  | 
|   704             if ((p + 1) < (fn + buflen)) { |  | 
|   705                 *p++ = '\\'; |  | 
|   706                 *p = '\0'; |  | 
|   707                 slashAdded = PR_TRUE; |  | 
|   708             } else { |  | 
|   709                 return PR_FALSE; /* name too long */ |  | 
|   710             } |  | 
|   711         } |  | 
|   712         rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; |  | 
|   713         /* restore the 'fn' buffer */ |  | 
|   714         if (slashAdded) { |  | 
|   715             *--p = '\0'; |  | 
|   716         } |  | 
|   717     } |  | 
|   718     return rv; |  | 
|   719 } |  | 
|   720  |  | 
|   721 PRInt32 |  | 
|   722 _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) |  | 
|   723 { |  | 
|   724     WIN32_FILE_ATTRIBUTE_DATA findFileData; |  | 
|   725     BOOL rv; |  | 
|   726      |  | 
|   727     if (NULL == fn || '\0' == *fn) { |  | 
|   728         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |  | 
|   729         return -1; |  | 
|   730     } |  | 
|   731  |  | 
|   732     rv = GetFileAttributesEx(fn, GetFileExInfoStandard, &findFileData); |  | 
|   733     if (!rv) { |  | 
|   734         _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); |  | 
|   735         return -1; |  | 
|   736     } |  | 
|   737  |  | 
|   738     if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { |  | 
|   739         info->type = PR_FILE_DIRECTORY; |  | 
|   740     } else { |  | 
|   741         info->type = PR_FILE_FILE; |  | 
|   742     } |  | 
|   743  |  | 
|   744     info->size = findFileData.nFileSizeHigh; |  | 
|   745     info->size = (info->size << 32) + findFileData.nFileSizeLow; |  | 
|   746  |  | 
|   747     _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); |  | 
|   748  |  | 
|   749     if (0 == findFileData.ftCreationTime.dwLowDateTime && |  | 
|   750             0 == findFileData.ftCreationTime.dwHighDateTime) { |  | 
|   751         info->creationTime = info->modifyTime; |  | 
|   752     } else { |  | 
|   753         _PR_FileTimeToPRTime(&findFileData.ftCreationTime, |  | 
|   754                 &info->creationTime); |  | 
|   755     } |  | 
|   756  |  | 
|   757     return 0; |  | 
|   758 } |  | 
|   759  |  | 
|   760 PRInt32 |  | 
|   761 _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) |  | 
|   762 { |  | 
|   763     PRFileInfo64 info64; |  | 
|   764     PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64); |  | 
|   765     if (0 == rv) |  | 
|   766     { |  | 
|   767         info->type = info64.type; |  | 
|   768         info->size = (PRUint32) info64.size; |  | 
|   769         info->modifyTime = info64.modifyTime; |  | 
|   770         info->creationTime = info64.creationTime; |  | 
|   771     } |  | 
|   772     return rv; |  | 
|   773 } |  | 
|   774  |  | 
|   775 PRInt32 |  | 
|   776 _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) |  | 
|   777 { |  | 
|   778     int rv; |  | 
|   779  |  | 
|   780     BY_HANDLE_FILE_INFORMATION hinfo; |  | 
|   781  |  | 
|   782     rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo); |  | 
|   783     if (rv == FALSE) { |  | 
|   784                 _PR_MD_MAP_FSTAT_ERROR(GetLastError()); |  | 
|   785         return -1; |  | 
|   786         } |  | 
|   787  |  | 
|   788     if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |  | 
|   789         info->type = PR_FILE_DIRECTORY; |  | 
|   790     else |  | 
|   791         info->type = PR_FILE_FILE; |  | 
|   792  |  | 
|   793     info->size = hinfo.nFileSizeHigh; |  | 
|   794     info->size = (info->size << 32) + hinfo.nFileSizeLow; |  | 
|   795  |  | 
|   796     _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) ); |  | 
|   797     _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) ); |  | 
|   798  |  | 
|   799     return 0; |  | 
|   800 } |  | 
|   801  |  | 
|   802 PRInt32 |  | 
|   803 _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) |  | 
|   804 { |  | 
|   805     PRFileInfo64 info64; |  | 
|   806     int rv = _PR_MD_GETOPENFILEINFO64(fd, &info64); |  | 
|   807     if (0 == rv) |  | 
|   808     { |  | 
|   809         info->type = info64.type; |  | 
|   810         info->modifyTime = info64.modifyTime; |  | 
|   811         info->creationTime = info64.creationTime; |  | 
|   812         LL_L2I(info->size, info64.size); |  | 
|   813     } |  | 
|   814     return rv; |  | 
|   815 } |  | 
|   816  |  | 
|   817 PRStatus |  | 
|   818 _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) |  | 
|   819 { |  | 
|   820     BOOL rv; |  | 
|   821  |  | 
|   822     /* |  | 
|   823      * The SetHandleInformation function fails with the |  | 
|   824      * ERROR_CALL_NOT_IMPLEMENTED error on Win95. |  | 
|   825      */ |  | 
|   826     rv = SetHandleInformation( |  | 
|   827             (HANDLE)fd->secret->md.osfd, |  | 
|   828             HANDLE_FLAG_INHERIT, |  | 
|   829             inheritable ? HANDLE_FLAG_INHERIT : 0); |  | 
|   830     if (0 == rv) { |  | 
|   831         _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); |  | 
|   832         return PR_FAILURE; |  | 
|   833     } |  | 
|   834     return PR_SUCCESS; |  | 
|   835 }  |  | 
|   836  |  | 
|   837 void |  | 
|   838 _PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) |  | 
|   839 { |  | 
|   840     if (imported) { |  | 
|   841         fd->secret->inheritable = _PR_TRI_UNKNOWN; |  | 
|   842     } else { |  | 
|   843         fd->secret->inheritable = _PR_TRI_FALSE; |  | 
|   844     } |  | 
|   845 } |  | 
|   846  |  | 
|   847 void |  | 
|   848 _PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) |  | 
|   849 { |  | 
|   850     DWORD flags; |  | 
|   851  |  | 
|   852     PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); |  | 
|   853     if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) { |  | 
|   854         if (flags & HANDLE_FLAG_INHERIT) { |  | 
|   855             fd->secret->inheritable = _PR_TRI_TRUE; |  | 
|   856         } else { |  | 
|   857             fd->secret->inheritable = _PR_TRI_FALSE; |  | 
|   858         } |  | 
|   859     } |  | 
|   860 } |  | 
|   861  |  | 
|   862 PRInt32 |  | 
|   863 _PR_MD_RENAME(const char *from, const char *to) |  | 
|   864 { |  | 
|   865     /* Does this work with dot-relative pathnames? */ |  | 
|   866     if (MoveFileA(from, to)) { |  | 
|   867         return 0; |  | 
|   868     } else { |  | 
|   869                 _PR_MD_MAP_RENAME_ERROR(GetLastError()); |  | 
|   870         return -1; |  | 
|   871     } |  | 
|   872 } |  | 
|   873  |  | 
|   874 PRInt32 |  | 
|   875 _PR_MD_ACCESS(const char *name, PRAccessHow how) |  | 
|   876 { |  | 
|   877 PRInt32 rv; |  | 
|   878     switch (how) { |  | 
|   879       case PR_ACCESS_WRITE_OK: |  | 
|   880         rv = _access(name, 02); |  | 
|   881                 break; |  | 
|   882       case PR_ACCESS_READ_OK: |  | 
|   883         rv = _access(name, 04); |  | 
|   884                 break; |  | 
|   885       case PR_ACCESS_EXISTS: |  | 
|   886         return _access(name, 00); |  | 
|   887                 break; |  | 
|   888       default: |  | 
|   889                 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |  | 
|   890                 return -1; |  | 
|   891     } |  | 
|   892         if (rv < 0) |  | 
|   893                 _PR_MD_MAP_ACCESS_ERROR(errno); |  | 
|   894     return rv; |  | 
|   895 } |  | 
|   896  |  | 
|   897 PRInt32 |  | 
|   898 _PR_MD_MKDIR(const char *name, PRIntn mode) |  | 
|   899 { |  | 
|   900     /* XXXMB - how to translate the "mode"??? */ |  | 
|   901     if (CreateDirectoryA(name, NULL)) { |  | 
|   902         return 0; |  | 
|   903     } else { |  | 
|   904                 _PR_MD_MAP_MKDIR_ERROR(GetLastError()); |  | 
|   905         return -1; |  | 
|   906     } |  | 
|   907 } |  | 
|   908  |  | 
|   909 PRInt32 |  | 
|   910 _PR_MD_MAKE_DIR(const char *name, PRIntn mode) |  | 
|   911 { |  | 
|   912     BOOL rv; |  | 
|   913     SECURITY_ATTRIBUTES sa; |  | 
|   914     LPSECURITY_ATTRIBUTES lpSA = NULL; |  | 
|   915     PSECURITY_DESCRIPTOR pSD = NULL; |  | 
|   916     PACL pACL = NULL; |  | 
|   917  |  | 
|   918     if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable, |  | 
|   919             &pSD, &pACL) == PR_SUCCESS) { |  | 
|   920         sa.nLength = sizeof(sa); |  | 
|   921         sa.lpSecurityDescriptor = pSD; |  | 
|   922         sa.bInheritHandle = FALSE; |  | 
|   923         lpSA = &sa; |  | 
|   924     } |  | 
|   925     rv = CreateDirectoryA(name, lpSA); |  | 
|   926     if (lpSA != NULL) { |  | 
|   927         _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); |  | 
|   928     } |  | 
|   929     if (rv) { |  | 
|   930         return 0; |  | 
|   931     } else { |  | 
|   932         _PR_MD_MAP_MKDIR_ERROR(GetLastError()); |  | 
|   933         return -1; |  | 
|   934     } |  | 
|   935 } |  | 
|   936  |  | 
|   937 PRInt32 |  | 
|   938 _PR_MD_RMDIR(const char *name) |  | 
|   939 { |  | 
|   940     if (RemoveDirectoryA(name)) { |  | 
|   941         return 0; |  | 
|   942     } else { |  | 
|   943                 _PR_MD_MAP_RMDIR_ERROR(GetLastError()); |  | 
|   944         return -1; |  | 
|   945     } |  | 
|   946 } |  | 
|   947  |  | 
|   948 PRStatus |  | 
|   949 _PR_MD_LOCKFILE(PROsfd f) |  | 
|   950 { |  | 
|   951     PRStatus  rc = PR_SUCCESS; |  | 
|   952         DWORD     rv; |  | 
|   953  |  | 
|   954         rv = LockFile( (HANDLE)f, |  | 
|   955                 0l, 0l, |  | 
|   956                 0x0l, 0xffffffffl );  |  | 
|   957         if ( rv == 0 ) { |  | 
|   958         DWORD err = GetLastError(); |  | 
|   959         _PR_MD_MAP_DEFAULT_ERROR(err); |  | 
|   960         PR_LOG( _pr_io_lm, PR_LOG_ERROR, |  | 
|   961             ("_PR_MD_LOCKFILE() failed. Error: %d", err )); |  | 
|   962         rc = PR_FAILURE; |  | 
|   963     } |  | 
|   964  |  | 
|   965     return rc; |  | 
|   966 } /* end _PR_MD_LOCKFILE() */ |  | 
|   967  |  | 
|   968 PRStatus |  | 
|   969 _PR_MD_TLOCKFILE(PROsfd f) |  | 
|   970 { |  | 
|   971     PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); |  | 
|   972     return PR_FAILURE; |  | 
|   973 } /* end _PR_MD_TLOCKFILE() */ |  | 
|   974  |  | 
|   975  |  | 
|   976 PRStatus |  | 
|   977 _PR_MD_UNLOCKFILE(PROsfd f) |  | 
|   978 { |  | 
|   979         PRInt32   rv; |  | 
|   980      |  | 
|   981     rv = UnlockFile( (HANDLE) f, |  | 
|   982                 0l, 0l, |  | 
|   983             0x0l, 0xffffffffl );  |  | 
|   984              |  | 
|   985     if ( rv ) |  | 
|   986     { |  | 
|   987         return PR_SUCCESS; |  | 
|   988     } |  | 
|   989     else |  | 
|   990     { |  | 
|   991                 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); |  | 
|   992                 return PR_FAILURE; |  | 
|   993     } |  | 
|   994 } /* end _PR_MD_UNLOCKFILE() */ |  | 
|   995  |  | 
|   996 PRInt32 |  | 
|   997 _PR_MD_PIPEAVAILABLE(PRFileDesc *fd) |  | 
|   998 { |  | 
|   999     if (NULL == fd) |  | 
|  1000                 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); |  | 
|  1001         else |  | 
|  1002                 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); |  | 
|  1003     return -1; |  | 
|  1004 } |  | 
|  1005  |  | 
|  1006 #ifdef MOZ_UNICODE |  | 
|  1007  |  | 
|  1008 typedef HANDLE (WINAPI *CreateFileWFn) (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIB
      UTES, DWORD, DWORD, HANDLE); |  | 
|  1009 static CreateFileWFn createFileW = CreateFileW; |  | 
|  1010 typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW); |  | 
|  1011 static FindFirstFileWFn findFirstFileW = FindFirstFileW; |  | 
|  1012 typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW); |  | 
|  1013 static FindNextFileWFn findNextFileW = FindNextFileW; |  | 
|  1014 typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *); |  | 
|  1015 static GetFullPathNameWFn getFullPathNameW = GetFullPathNameW; |  | 
|  1016 typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR); |  | 
|  1017 static GetDriveTypeWFn getDriveTypeW = GetDriveTypeW; |  | 
|  1018  |  | 
|  1019 #endif /* MOZ_UNICODE */ |  | 
|  1020  |  | 
|  1021 #ifdef MOZ_UNICODE |  | 
|  1022  |  | 
|  1023 /* ================ UTF16 Interfaces ================================ */ |  | 
|  1024 static void FlipSlashesW(PRUnichar *cp, size_t len) |  | 
|  1025 { |  | 
|  1026     while (len-- > 0) { |  | 
|  1027         if (cp[0] == L'/') { |  | 
|  1028             cp[0] = L'\\'; |  | 
|  1029         } |  | 
|  1030         cp++; |  | 
|  1031     } |  | 
|  1032 } /* end FlipSlashesW() */ |  | 
|  1033  |  | 
|  1034 PROsfd |  | 
|  1035 _PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, int mode) |  | 
|  1036 { |  | 
|  1037     HANDLE file; |  | 
|  1038     PRInt32 access = 0; |  | 
|  1039     PRInt32 flags = 0; |  | 
|  1040     PRInt32 flag6 = 0; |  | 
|  1041     SECURITY_ATTRIBUTES sa; |  | 
|  1042     LPSECURITY_ATTRIBUTES lpSA = NULL; |  | 
|  1043     PSECURITY_DESCRIPTOR pSD = NULL; |  | 
|  1044     PACL pACL = NULL; |  | 
|  1045  |  | 
|  1046     if (osflags & PR_CREATE_FILE) { |  | 
|  1047         if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, |  | 
|  1048                 &pSD, &pACL) == PR_SUCCESS) { |  | 
|  1049             sa.nLength = sizeof(sa); |  | 
|  1050             sa.lpSecurityDescriptor = pSD; |  | 
|  1051             sa.bInheritHandle = FALSE; |  | 
|  1052             lpSA = &sa; |  | 
|  1053         } |  | 
|  1054     } |  | 
|  1055  |  | 
|  1056     if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; |  | 
|  1057  |  | 
|  1058     if (osflags & PR_RDONLY || osflags & PR_RDWR) |  | 
|  1059         access |= GENERIC_READ; |  | 
|  1060     if (osflags & PR_WRONLY || osflags & PR_RDWR) |  | 
|  1061         access |= GENERIC_WRITE; |  | 
|  1062   |  | 
|  1063     if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) |  | 
|  1064         flags = CREATE_NEW; |  | 
|  1065     else if (osflags & PR_CREATE_FILE) { |  | 
|  1066         if (osflags & PR_TRUNCATE) |  | 
|  1067             flags = CREATE_ALWAYS; |  | 
|  1068         else |  | 
|  1069             flags = OPEN_ALWAYS; |  | 
|  1070     } else { |  | 
|  1071         if (osflags & PR_TRUNCATE) |  | 
|  1072             flags = TRUNCATE_EXISTING; |  | 
|  1073         else |  | 
|  1074             flags = OPEN_EXISTING; |  | 
|  1075     } |  | 
|  1076  |  | 
|  1077     file = createFileW(name, |  | 
|  1078                        access, |  | 
|  1079                        FILE_SHARE_READ|FILE_SHARE_WRITE, |  | 
|  1080                        lpSA, |  | 
|  1081                        flags, |  | 
|  1082                        flag6, |  | 
|  1083                        NULL); |  | 
|  1084     if (lpSA != NULL) { |  | 
|  1085         _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); |  | 
|  1086     } |  | 
|  1087     if (file == INVALID_HANDLE_VALUE) { |  | 
|  1088         _PR_MD_MAP_OPEN_ERROR(GetLastError()); |  | 
|  1089         return -1; |  | 
|  1090     } |  | 
|  1091   |  | 
|  1092     return (PROsfd)file; |  | 
|  1093 } |  | 
|  1094   |  | 
|  1095 PRStatus |  | 
|  1096 _PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name) |  | 
|  1097 { |  | 
|  1098     PRUnichar filename[ MAX_PATH ]; |  | 
|  1099     int len; |  | 
|  1100  |  | 
|  1101     len = wcslen(name); |  | 
|  1102     /* Need 5 bytes for \*.* and the trailing null byte. */ |  | 
|  1103     if (len + 5 > MAX_PATH) { |  | 
|  1104         PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); |  | 
|  1105         return PR_FAILURE; |  | 
|  1106     } |  | 
|  1107     wcscpy(filename, name); |  | 
|  1108  |  | 
|  1109     /* |  | 
|  1110      * If 'name' ends in a slash or backslash, do not append |  | 
|  1111      * another backslash. |  | 
|  1112      */ |  | 
|  1113     if (filename[len - 1] == L'/' || filename[len - 1] == L'\\') { |  | 
|  1114         len--; |  | 
|  1115     } |  | 
|  1116     wcscpy(&filename[len], L"\\*.*"); |  | 
|  1117     FlipSlashesW( filename, wcslen(filename) ); |  | 
|  1118  |  | 
|  1119     d->d_hdl = findFirstFileW( filename, &(d->d_entry) ); |  | 
|  1120     if ( d->d_hdl == INVALID_HANDLE_VALUE ) { |  | 
|  1121         _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); |  | 
|  1122         return PR_FAILURE; |  | 
|  1123     } |  | 
|  1124     d->firstEntry = PR_TRUE; |  | 
|  1125     d->magic = _MD_MAGIC_DIR; |  | 
|  1126     return PR_SUCCESS; |  | 
|  1127 } |  | 
|  1128  |  | 
|  1129 PRUnichar * |  | 
|  1130 _PR_MD_READ_DIR_UTF16(_MDDirUTF16 *d, PRIntn flags) |  | 
|  1131 { |  | 
|  1132     PRInt32 err; |  | 
|  1133     BOOL rv; |  | 
|  1134     PRUnichar *fileName; |  | 
|  1135  |  | 
|  1136     if ( d ) { |  | 
|  1137         while (1) { |  | 
|  1138             if (d->firstEntry) { |  | 
|  1139                 d->firstEntry = PR_FALSE; |  | 
|  1140                 rv = 1; |  | 
|  1141             } else { |  | 
|  1142                 rv = findNextFileW(d->d_hdl, &(d->d_entry)); |  | 
|  1143             } |  | 
|  1144             if (rv == 0) { |  | 
|  1145                 break; |  | 
|  1146             } |  | 
|  1147             fileName = GetFileFromDIR(d); |  | 
|  1148             if ( (flags & PR_SKIP_DOT) && |  | 
|  1149                  (fileName[0] == L'.') && (fileName[1] == L'\0')) |  | 
|  1150                 continue; |  | 
|  1151             if ( (flags & PR_SKIP_DOT_DOT) && |  | 
|  1152                  (fileName[0] == L'.') && (fileName[1] == L'.') && |  | 
|  1153                  (fileName[2] == L'\0')) |  | 
|  1154                 continue; |  | 
|  1155             if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) |  | 
|  1156                 continue; |  | 
|  1157             return fileName; |  | 
|  1158         } |  | 
|  1159         err = GetLastError(); |  | 
|  1160         PR_ASSERT(NO_ERROR != err); |  | 
|  1161         _PR_MD_MAP_READDIR_ERROR(err); |  | 
|  1162         return NULL; |  | 
|  1163     } |  | 
|  1164     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |  | 
|  1165     return NULL; |  | 
|  1166 } |  | 
|  1167   |  | 
|  1168 PRInt32 |  | 
|  1169 _PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *d) |  | 
|  1170 { |  | 
|  1171     if ( d ) { |  | 
|  1172         if (FindClose(d->d_hdl)) { |  | 
|  1173             d->magic = (PRUint32)-1; |  | 
|  1174             return 0; |  | 
|  1175         } else { |  | 
|  1176             _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); |  | 
|  1177             return -1; |  | 
|  1178         } |  | 
|  1179     } |  | 
|  1180     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |  | 
|  1181     return -1; |  | 
|  1182 } |  | 
|  1183  |  | 
|  1184 #define _PR_IS_W_SLASH(ch) ((ch) == L'/' || (ch) == L'\\') |  | 
|  1185  |  | 
|  1186 /* |  | 
|  1187  * IsRootDirectoryW -- |  | 
|  1188  * |  | 
|  1189  * Return PR_TRUE if the pathname 'fn' is a valid root directory, |  | 
|  1190  * else return PR_FALSE.  The PRUnichar buffer pointed to by 'fn' must |  | 
|  1191  * be writable.  During the execution of this function, the contents |  | 
|  1192  * of the buffer pointed to by 'fn' may be modified, but on return |  | 
|  1193  * the original contents will be restored.  'buflen' is the size of |  | 
|  1194  * the buffer pointed to by 'fn', in PRUnichars. |  | 
|  1195  * |  | 
|  1196  * Root directories come in three formats: |  | 
|  1197  * 1. / or \, meaning the root directory of the current drive. |  | 
|  1198  * 2. C:/ or C:\, where C is a drive letter. |  | 
|  1199  * 3. \\<server name>\<share point name>\ or |  | 
|  1200  *    \\<server name>\<share point name>, meaning the root directory |  | 
|  1201  *    of a UNC (Universal Naming Convention) name. |  | 
|  1202  */ |  | 
|  1203  |  | 
|  1204 static PRBool |  | 
|  1205 IsRootDirectoryW(PRUnichar *fn, size_t buflen) |  | 
|  1206 { |  | 
|  1207     PRUnichar *p; |  | 
|  1208     PRBool slashAdded = PR_FALSE; |  | 
|  1209     PRBool rv = PR_FALSE; |  | 
|  1210  |  | 
|  1211     if (_PR_IS_W_SLASH(fn[0]) && fn[1] == L'\0') { |  | 
|  1212         return PR_TRUE; |  | 
|  1213     } |  | 
|  1214  |  | 
|  1215     if (iswalpha(fn[0]) && fn[1] == L':' && _PR_IS_W_SLASH(fn[2]) |  | 
|  1216             && fn[3] == L'\0') { |  | 
|  1217         rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE; |  | 
|  1218         return rv; |  | 
|  1219     } |  | 
|  1220  |  | 
|  1221     /* The UNC root directory */ |  | 
|  1222  |  | 
|  1223     if (_PR_IS_W_SLASH(fn[0]) && _PR_IS_W_SLASH(fn[1])) { |  | 
|  1224         /* The 'server' part should have at least one character. */ |  | 
|  1225         p = &fn[2]; |  | 
|  1226         if (*p == L'\0' || _PR_IS_W_SLASH(*p)) { |  | 
|  1227             return PR_FALSE; |  | 
|  1228         } |  | 
|  1229  |  | 
|  1230         /* look for the next slash */ |  | 
|  1231         do { |  | 
|  1232             p++; |  | 
|  1233         } while (*p != L'\0' && !_PR_IS_W_SLASH(*p)); |  | 
|  1234         if (*p == L'\0') { |  | 
|  1235             return PR_FALSE; |  | 
|  1236         } |  | 
|  1237  |  | 
|  1238         /* The 'share' part should have at least one character. */ |  | 
|  1239         p++; |  | 
|  1240         if (*p == L'\0' || _PR_IS_W_SLASH(*p)) { |  | 
|  1241             return PR_FALSE; |  | 
|  1242         } |  | 
|  1243  |  | 
|  1244         /* look for the final slash */ |  | 
|  1245         do { |  | 
|  1246             p++; |  | 
|  1247         } while (*p != L'\0' && !_PR_IS_W_SLASH(*p)); |  | 
|  1248         if (_PR_IS_W_SLASH(*p) && p[1] != L'\0') { |  | 
|  1249             return PR_FALSE; |  | 
|  1250         } |  | 
|  1251         if (*p == L'\0') { |  | 
|  1252             /* |  | 
|  1253              * GetDriveType() doesn't work correctly if the |  | 
|  1254              * path is of the form \\server\share, so we add |  | 
|  1255              * a final slash temporarily. |  | 
|  1256              */ |  | 
|  1257             if ((p + 1) < (fn + buflen)) { |  | 
|  1258                 *p++ = L'\\'; |  | 
|  1259                 *p = L'\0'; |  | 
|  1260                 slashAdded = PR_TRUE; |  | 
|  1261             } else { |  | 
|  1262                 return PR_FALSE; /* name too long */ |  | 
|  1263             } |  | 
|  1264         } |  | 
|  1265         rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE; |  | 
|  1266         /* restore the 'fn' buffer */ |  | 
|  1267         if (slashAdded) { |  | 
|  1268             *--p = L'\0'; |  | 
|  1269         } |  | 
|  1270     } |  | 
|  1271     return rv; |  | 
|  1272 } |  | 
|  1273  |  | 
|  1274 PRInt32 |  | 
|  1275 _PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info) |  | 
|  1276 { |  | 
|  1277     HANDLE hFindFile; |  | 
|  1278     WIN32_FIND_DATAW findFileData; |  | 
|  1279     PRUnichar pathbuf[MAX_PATH + 1]; |  | 
|  1280  |  | 
|  1281     if (NULL == fn || L'\0' == *fn) { |  | 
|  1282         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |  | 
|  1283         return -1; |  | 
|  1284     } |  | 
|  1285  |  | 
|  1286     /* |  | 
|  1287      * FindFirstFile() expands wildcard characters.  So |  | 
|  1288      * we make sure the pathname contains no wildcard. |  | 
|  1289      */ |  | 
|  1290     if (NULL != wcspbrk(fn, L"?*")) { |  | 
|  1291         PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0); |  | 
|  1292         return -1; |  | 
|  1293     } |  | 
|  1294  |  | 
|  1295     hFindFile = findFirstFileW(fn, &findFileData); |  | 
|  1296     if (INVALID_HANDLE_VALUE == hFindFile) { |  | 
|  1297         DWORD len; |  | 
|  1298         PRUnichar *filePart; |  | 
|  1299  |  | 
|  1300         /* |  | 
|  1301          * FindFirstFile() does not work correctly on root directories. |  | 
|  1302          * It also doesn't work correctly on a pathname that ends in a |  | 
|  1303          * slash.  So we first check to see if the pathname specifies a |  | 
|  1304          * root directory.  If not, and if the pathname ends in a slash, |  | 
|  1305          * we remove the final slash and try again. |  | 
|  1306          */ |  | 
|  1307  |  | 
|  1308         /* |  | 
|  1309          * If the pathname does not contain ., \, and /, it cannot be |  | 
|  1310          * a root directory or a pathname that ends in a slash. |  | 
|  1311          */ |  | 
|  1312         if (NULL == wcspbrk(fn, L".\\/")) { |  | 
|  1313             _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); |  | 
|  1314             return -1; |  | 
|  1315         }  |  | 
|  1316         len = getFullPathNameW(fn, sizeof(pathbuf)/sizeof(pathbuf[0]), pathbuf, |  | 
|  1317                 &filePart); |  | 
|  1318         if (0 == len) { |  | 
|  1319             _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); |  | 
|  1320             return -1; |  | 
|  1321         } |  | 
|  1322         if (len > sizeof(pathbuf)/sizeof(pathbuf[0])) { |  | 
|  1323             PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); |  | 
|  1324             return -1; |  | 
|  1325         } |  | 
|  1326         if (IsRootDirectoryW(pathbuf, sizeof(pathbuf)/sizeof(pathbuf[0]))) { |  | 
|  1327             info->type = PR_FILE_DIRECTORY; |  | 
|  1328             info->size = 0; |  | 
|  1329             /* |  | 
|  1330              * These timestamps don't make sense for root directories. |  | 
|  1331              */ |  | 
|  1332             info->modifyTime = 0; |  | 
|  1333             info->creationTime = 0; |  | 
|  1334             return 0; |  | 
|  1335         } |  | 
|  1336         if (!_PR_IS_W_SLASH(pathbuf[len - 1])) { |  | 
|  1337             _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); |  | 
|  1338             return -1; |  | 
|  1339         } else { |  | 
|  1340             pathbuf[len - 1] = L'\0'; |  | 
|  1341             hFindFile = findFirstFileW(pathbuf, &findFileData); |  | 
|  1342             if (INVALID_HANDLE_VALUE == hFindFile) { |  | 
|  1343                 _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); |  | 
|  1344                 return -1; |  | 
|  1345             } |  | 
|  1346         } |  | 
|  1347     } |  | 
|  1348  |  | 
|  1349     FindClose(hFindFile); |  | 
|  1350  |  | 
|  1351     if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { |  | 
|  1352         info->type = PR_FILE_DIRECTORY; |  | 
|  1353     } else { |  | 
|  1354         info->type = PR_FILE_FILE; |  | 
|  1355     } |  | 
|  1356  |  | 
|  1357     info->size = findFileData.nFileSizeHigh; |  | 
|  1358     info->size = (info->size << 32) + findFileData.nFileSizeLow; |  | 
|  1359  |  | 
|  1360     _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); |  | 
|  1361  |  | 
|  1362     if (0 == findFileData.ftCreationTime.dwLowDateTime && |  | 
|  1363             0 == findFileData.ftCreationTime.dwHighDateTime) { |  | 
|  1364         info->creationTime = info->modifyTime; |  | 
|  1365     } else { |  | 
|  1366         _PR_FileTimeToPRTime(&findFileData.ftCreationTime, |  | 
|  1367                 &info->creationTime); |  | 
|  1368     } |  | 
|  1369  |  | 
|  1370     return 0; |  | 
|  1371 } |  | 
|  1372 /* ================ end of UTF16 Interfaces ================================ */ |  | 
|  1373 #endif /* MOZ_UNICODE */ |  | 
| OLD | NEW |