| 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 |