| 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 #ifdef WINCE | |
| 20 | |
| 21 static HANDLE CreateFileA(LPCSTR lpFileName, | |
| 22 DWORD dwDesiredAccess, | |
| 23 DWORD dwShareMode, | |
| 24 LPSECURITY_ATTRIBUTES lpSecurityAttributes, | |
| 25 DWORD dwCreationDisposition, | |
| 26 DWORD dwFlagsAndAttributes, | |
| 27 HANDLE hTemplateFile) | |
| 28 { | |
| 29 PRUnichar wFileName[MAX_PATH]; | |
| 30 MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH); | |
| 31 return CreateFileW(wFileName, dwDesiredAccess, dwShareMode, | |
| 32 lpSecurityAttributes, dwCreationDisposition, | |
| 33 dwFlagsAndAttributes, hTemplateFile); | |
| 34 } | |
| 35 | |
| 36 /* | |
| 37 * We seem to call FindFirstFileA and FindNextFileA just to get | |
| 38 * the file names in a directory listing. If so, we could define | |
| 39 * a custom WIN32_FIND_DATAA structure with just the cFileName | |
| 40 * member, and the CopyFindFileDataW2A function could just | |
| 41 * copy/convert the cFileName member. | |
| 42 */ | |
| 43 static void CopyFindFileDataW2A(LPWIN32_FIND_DATAW from, | |
| 44 LPWIN32_FIND_DATAA to) | |
| 45 { | |
| 46 /* | |
| 47 * WIN32_FIND_DATAA and WIN32_FIND_DATAW are slightly different. | |
| 48 * The dwReserved0, dwReserved1, and cAlternateFileName members | |
| 49 * exist only in WIN32_FIND_DATAA. The dwOID member exists only | |
| 50 * in WIN32_FIND_DATAW. | |
| 51 */ | |
| 52 to->dwFileAttributes = from->dwFileAttributes; | |
| 53 to->ftCreationTime = from->ftCreationTime; | |
| 54 to->ftLastAccessTime = from->ftLastAccessTime; | |
| 55 to->ftLastWriteTime = from->ftLastWriteTime; | |
| 56 to->nFileSizeHigh = from->nFileSizeHigh; | |
| 57 to->nFileSizeLow = from->nFileSizeLow; | |
| 58 to->dwReserved0 = 0; | |
| 59 to->dwReserved1 = 0; | |
| 60 WideCharToMultiByte(CP_ACP, 0, from->cFileName, -1, | |
| 61 to->cFileName, MAX_PATH, NULL, NULL); | |
| 62 to->cAlternateFileName[0] = '\0'; | |
| 63 } | |
| 64 | |
| 65 static HANDLE FindFirstFileA(LPCSTR lpFileName, | |
| 66 LPWIN32_FIND_DATAA lpFindFileData) | |
| 67 { | |
| 68 PRUnichar wFileName[MAX_PATH]; | |
| 69 HANDLE hFindFile; | |
| 70 WIN32_FIND_DATAW wFindFileData; | |
| 71 | |
| 72 MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH); | |
| 73 hFindFile = FindFirstFileW(wFileName, &wFindFileData); | |
| 74 if (hFindFile != INVALID_HANDLE_VALUE) { | |
| 75 CopyFindFileDataW2A(&wFindFileData, lpFindFileData); | |
| 76 } | |
| 77 return hFindFile; | |
| 78 } | |
| 79 | |
| 80 static BOOL FindNextFileA(HANDLE hFindFile, | |
| 81 LPWIN32_FIND_DATAA lpFindFileData) | |
| 82 { | |
| 83 WIN32_FIND_DATAW wFindFileData; | |
| 84 BOOL rv; | |
| 85 | |
| 86 rv = FindNextFileW(hFindFile, &wFindFileData); | |
| 87 if (rv) { | |
| 88 CopyFindFileDataW2A(&wFindFileData, lpFindFileData); | |
| 89 } | |
| 90 return rv; | |
| 91 } | |
| 92 | |
| 93 static BOOL GetFileAttributesExA(LPCSTR lpFileName, | |
| 94 GET_FILEEX_INFO_LEVELS fInfoLevelId, | |
| 95 LPVOID lpFileInformation) | |
| 96 { | |
| 97 PRUnichar wFileName[MAX_PATH]; | |
| 98 MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH); | |
| 99 return GetFileAttributesExW(wFileName, fInfoLevelId, lpFileInformation); | |
| 100 } | |
| 101 | |
| 102 static BOOL DeleteFileA(LPCSTR lpFileName) | |
| 103 { | |
| 104 PRUnichar wFileName[MAX_PATH]; | |
| 105 MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH); | |
| 106 return DeleteFileW(wFileName); | |
| 107 } | |
| 108 | |
| 109 static BOOL MoveFileA(LPCSTR from, LPCSTR to) | |
| 110 { | |
| 111 PRUnichar wFrom[MAX_PATH]; | |
| 112 PRUnichar wTo[MAX_PATH]; | |
| 113 MultiByteToWideChar(CP_ACP, 0, from, -1, wFrom, MAX_PATH); | |
| 114 MultiByteToWideChar(CP_ACP, 0, to, -1, wTo, MAX_PATH); | |
| 115 return MoveFileW(wFrom, wTo); | |
| 116 } | |
| 117 | |
| 118 static BOOL CreateDirectoryA(LPCSTR lpPathName, | |
| 119 LPSECURITY_ATTRIBUTES lpSecurityAttributes) | |
| 120 { | |
| 121 PRUnichar wPathName[MAX_PATH]; | |
| 122 MultiByteToWideChar(CP_ACP, 0, lpPathName, -1, wPathName, MAX_PATH); | |
| 123 return CreateDirectoryW(wPathName, lpSecurityAttributes); | |
| 124 } | |
| 125 | |
| 126 static BOOL RemoveDirectoryA(LPCSTR lpPathName) | |
| 127 { | |
| 128 PRUnichar wPathName[MAX_PATH]; | |
| 129 MultiByteToWideChar(CP_ACP, 0, lpPathName, -1, wPathName, MAX_PATH); | |
| 130 return RemoveDirectoryW(wPathName); | |
| 131 } | |
| 132 | |
| 133 static long GetDriveType(const char *lpRootPathName) | |
| 134 { | |
| 135 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
| 136 return 0; // The drive type cannot be determined. | |
| 137 } | |
| 138 | |
| 139 static DWORD GetFullPathName(const char *lpFileName, | |
| 140 DWORD nBufferLength, | |
| 141 const char *lpBuffer, | |
| 142 const char **lpFilePart) | |
| 143 { | |
| 144 // needs work dft | |
| 145 DWORD len = strlen(lpFileName); | |
| 146 if (len > nBufferLength) | |
| 147 return len; | |
| 148 | |
| 149 strncpy((char *)lpBuffer, lpFileName, len); | |
| 150 ((char *)lpBuffer)[len] = '\0'; | |
| 151 | |
| 152 if (lpFilePart) { | |
| 153 char *sep = strrchr(lpBuffer, '\\'); | |
| 154 if (sep) { | |
| 155 sep++; // pass the seperator | |
| 156 *lpFilePart = sep; | |
| 157 } else { | |
| 158 *lpFilePart = lpBuffer; | |
| 159 } | |
| 160 } | |
| 161 return len; | |
| 162 } | |
| 163 | |
| 164 static BOOL LockFile(HANDLE hFile, | |
| 165 DWORD dwFileOffsetLow, | |
| 166 DWORD dwFileOffsetHigh, | |
| 167 DWORD nNumberOfBytesToLockLow, | |
| 168 DWORD nNumberOfBytesToLockHigh) | |
| 169 { | |
| 170 OVERLAPPED overlapped = {0}; | |
| 171 overlapped.Offset = dwFileOffsetLow; | |
| 172 overlapped.OffsetHigh = dwFileOffsetHigh; | |
| 173 return LockFileEx(hFile, | |
| 174 LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, | |
| 175 0, // reserved | |
| 176 nNumberOfBytesToLockLow, | |
| 177 nNumberOfBytesToLockHigh, &overlapped); | |
| 178 } | |
| 179 | |
| 180 static BOOL UnlockFile(HANDLE hFile, | |
| 181 DWORD dwFileOffsetLow, | |
| 182 DWORD dwFileOffsetHigh, | |
| 183 DWORD nNumberOfBytesToUnlockLow, | |
| 184 DWORD nNumberOfBytesToUnlockHigh) | |
| 185 { | |
| 186 OVERLAPPED overlapped = {0}; | |
| 187 overlapped.Offset = dwFileOffsetLow; | |
| 188 overlapped.OffsetHigh = dwFileOffsetHigh; | |
| 189 return UnlockFileEx(hFile, | |
| 190 0, // reserved | |
| 191 nNumberOfBytesToUnlockLow, | |
| 192 nNumberOfBytesToUnlockHigh, &overlapped); | |
| 193 } | |
| 194 | |
| 195 static unsigned char *_mbsdec(const unsigned char *string1, | |
| 196 const unsigned char *string2) | |
| 197 { | |
| 198 // needs work dft | |
| 199 return NULL; | |
| 200 } | |
| 201 | |
| 202 static unsigned char *_mbsinc(const unsigned char *inCurrent) | |
| 203 { | |
| 204 // needs work dft | |
| 205 return (unsigned char *)(inCurrent + 1); | |
| 206 } | |
| 207 | |
| 208 #endif | |
| 209 | |
| 210 struct _MDLock _pr_ioq_lock; | |
| 211 | |
| 212 /* | |
| 213 * NSPR-to-NT access right mapping table for files. | |
| 214 */ | |
| 215 static DWORD fileAccessTable[] = { | |
| 216 FILE_GENERIC_READ, | |
| 217 FILE_GENERIC_WRITE, | |
| 218 FILE_GENERIC_EXECUTE | |
| 219 }; | |
| 220 | |
| 221 /* | |
| 222 * NSPR-to-NT access right mapping table for directories. | |
| 223 */ | |
| 224 static DWORD dirAccessTable[] = { | |
| 225 FILE_GENERIC_READ, | |
| 226 FILE_GENERIC_WRITE|FILE_DELETE_CHILD, | |
| 227 FILE_GENERIC_EXECUTE | |
| 228 }; | |
| 229 | |
| 230 /* Windows CE has GetFileAttributesEx. */ | |
| 231 #ifndef WINCE | |
| 232 typedef BOOL (WINAPI *GetFileAttributesExFn)(LPCTSTR, | |
| 233 GET_FILEEX_INFO_LEVELS, | |
| 234 LPVOID); | |
| 235 static GetFileAttributesExFn getFileAttributesEx; | |
| 236 static void InitGetFileInfo(void); | |
| 237 #endif | |
| 238 | |
| 239 static void InitUnicodeSupport(void); | |
| 240 | |
| 241 static PRBool IsPrevCharSlash(const char *str, const char *current); | |
| 242 | |
| 243 void | |
| 244 _PR_MD_INIT_IO() | |
| 245 { | |
| 246 WORD WSAVersion = 0x0101; | |
| 247 WSADATA WSAData; | |
| 248 int err; | |
| 249 | |
| 250 err = WSAStartup( WSAVersion, &WSAData ); | |
| 251 PR_ASSERT(0 == err); | |
| 252 | |
| 253 #ifdef DEBUG | |
| 254 /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */ | |
| 255 { | |
| 256 SYSTEMTIME systime; | |
| 257 union { | |
| 258 PRTime prt; | |
| 259 FILETIME ft; | |
| 260 } filetime; | |
| 261 BOOL rv; | |
| 262 | |
| 263 systime.wYear = 1970; | |
| 264 systime.wMonth = 1; | |
| 265 /* wDayOfWeek is ignored */ | |
| 266 systime.wDay = 1; | |
| 267 systime.wHour = 0; | |
| 268 systime.wMinute = 0; | |
| 269 systime.wSecond = 0; | |
| 270 systime.wMilliseconds = 0; | |
| 271 | |
| 272 rv = SystemTimeToFileTime(&systime, &filetime.ft); | |
| 273 PR_ASSERT(0 != rv); | |
| 274 PR_ASSERT(filetime.prt == _pr_filetime_offset); | |
| 275 } | |
| 276 #endif /* DEBUG */ | |
| 277 | |
| 278 _PR_NT_InitSids(); | |
| 279 | |
| 280 #ifndef WINCE | |
| 281 InitGetFileInfo(); | |
| 282 #endif | |
| 283 | |
| 284 InitUnicodeSupport(); | |
| 285 | |
| 286 _PR_MD_InitSockets(); | |
| 287 } | |
| 288 | |
| 289 PRStatus | |
| 290 _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) | |
| 291 { | |
| 292 DWORD rv; | |
| 293 | |
| 294 PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? | |
| 295 INFINITE : PR_IntervalToMilliseconds(ticks); | |
| 296 rv = WaitForSingleObject(thread->md.blocked_sema, msecs); | |
| 297 switch(rv) | |
| 298 { | |
| 299 case WAIT_OBJECT_0: | |
| 300 return PR_SUCCESS; | |
| 301 break; | |
| 302 case WAIT_TIMEOUT: | |
| 303 _PR_THREAD_LOCK(thread); | |
| 304 if (thread->state == _PR_IO_WAIT) { | |
| 305 ; | |
| 306 } else { | |
| 307 if (thread->wait.cvar != NULL) { | |
| 308 thread->wait.cvar = NULL; | |
| 309 _PR_THREAD_UNLOCK(thread); | |
| 310 } else { | |
| 311 /* The CVAR was notified just as the timeout | |
| 312 * occurred. This led to us being notified twice. | |
| 313 * call WaitForSingleObject() to clear the semaphore. | |
| 314 */ | |
| 315 _PR_THREAD_UNLOCK(thread); | |
| 316 rv = WaitForSingleObject(thread->md.blocked_sema, 0); | |
| 317 PR_ASSERT(rv == WAIT_OBJECT_0); | |
| 318 } | |
| 319 } | |
| 320 return PR_SUCCESS; | |
| 321 break; | |
| 322 default: | |
| 323 return PR_FAILURE; | |
| 324 break; | |
| 325 } | |
| 326 } | |
| 327 PRStatus | |
| 328 _PR_MD_WAKEUP_WAITER(PRThread *thread) | |
| 329 { | |
| 330 if ( _PR_IS_NATIVE_THREAD(thread) ) | |
| 331 { | |
| 332 if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE) | |
| 333 return PR_FAILURE; | |
| 334 else | |
| 335 return PR_SUCCESS; | |
| 336 } | |
| 337 } | |
| 338 | |
| 339 | |
| 340 /* --- FILE IO ----------------------------------------------------------- */ | |
| 341 /* | |
| 342 * _PR_MD_OPEN() -- Open a file | |
| 343 * | |
| 344 * returns: a fileHandle | |
| 345 * | |
| 346 * The NSPR open flags (osflags) are translated into flags for Win95 | |
| 347 * | |
| 348 * Mode seems to be passed in as a unix style file permissions argument | |
| 349 * as in 0666, in the case of opening the logFile. | |
| 350 * | |
| 351 */ | |
| 352 PROsfd | |
| 353 _PR_MD_OPEN(const char *name, PRIntn osflags, int mode) | |
| 354 { | |
| 355 HANDLE file; | |
| 356 PRInt32 access = 0; | |
| 357 PRInt32 flags = 0; | |
| 358 PRInt32 flag6 = 0; | |
| 359 | |
| 360 if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; | |
| 361 | |
| 362 if (osflags & PR_RDONLY || osflags & PR_RDWR) | |
| 363 access |= GENERIC_READ; | |
| 364 if (osflags & PR_WRONLY || osflags & PR_RDWR) | |
| 365 access |= GENERIC_WRITE; | |
| 366 | |
| 367 if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) | |
| 368 flags = CREATE_NEW; | |
| 369 else if (osflags & PR_CREATE_FILE) { | |
| 370 if (osflags & PR_TRUNCATE) | |
| 371 flags = CREATE_ALWAYS; | |
| 372 else | |
| 373 flags = OPEN_ALWAYS; | |
| 374 } else { | |
| 375 if (osflags & PR_TRUNCATE) | |
| 376 flags = TRUNCATE_EXISTING; | |
| 377 else | |
| 378 flags = OPEN_EXISTING; | |
| 379 } | |
| 380 | |
| 381 file = CreateFileA(name, | |
| 382 access, | |
| 383 FILE_SHARE_READ|FILE_SHARE_WRITE, | |
| 384 NULL, | |
| 385 flags, | |
| 386 flag6, | |
| 387 NULL); | |
| 388 if (file == INVALID_HANDLE_VALUE) { | |
| 389 _PR_MD_MAP_OPEN_ERROR(GetLastError()); | |
| 390 return -1; | |
| 391 } | |
| 392 | |
| 393 return (PROsfd)file; | |
| 394 } | |
| 395 | |
| 396 PROsfd | |
| 397 _PR_MD_OPEN_FILE(const char *name, PRIntn osflags, int mode) | |
| 398 { | |
| 399 HANDLE file; | |
| 400 PRInt32 access = 0; | |
| 401 PRInt32 flags = 0; | |
| 402 PRInt32 flag6 = 0; | |
| 403 SECURITY_ATTRIBUTES sa; | |
| 404 LPSECURITY_ATTRIBUTES lpSA = NULL; | |
| 405 PSECURITY_DESCRIPTOR pSD = NULL; | |
| 406 PACL pACL = NULL; | |
| 407 | |
| 408 if (osflags & PR_CREATE_FILE) { | |
| 409 if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, | |
| 410 &pSD, &pACL) == PR_SUCCESS) { | |
| 411 sa.nLength = sizeof(sa); | |
| 412 sa.lpSecurityDescriptor = pSD; | |
| 413 sa.bInheritHandle = FALSE; | |
| 414 lpSA = &sa; | |
| 415 } | |
| 416 } | |
| 417 | |
| 418 if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; | |
| 419 | |
| 420 if (osflags & PR_RDONLY || osflags & PR_RDWR) | |
| 421 access |= GENERIC_READ; | |
| 422 if (osflags & PR_WRONLY || osflags & PR_RDWR) | |
| 423 access |= GENERIC_WRITE; | |
| 424 | |
| 425 if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) | |
| 426 flags = CREATE_NEW; | |
| 427 else if (osflags & PR_CREATE_FILE) { | |
| 428 if (osflags & PR_TRUNCATE) | |
| 429 flags = CREATE_ALWAYS; | |
| 430 else | |
| 431 flags = OPEN_ALWAYS; | |
| 432 } else { | |
| 433 if (osflags & PR_TRUNCATE) | |
| 434 flags = TRUNCATE_EXISTING; | |
| 435 else | |
| 436 flags = OPEN_EXISTING; | |
| 437 } | |
| 438 | |
| 439 file = CreateFileA(name, | |
| 440 access, | |
| 441 FILE_SHARE_READ|FILE_SHARE_WRITE, | |
| 442 lpSA, | |
| 443 flags, | |
| 444 flag6, | |
| 445 NULL); | |
| 446 if (lpSA != NULL) { | |
| 447 _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); | |
| 448 } | |
| 449 if (file == INVALID_HANDLE_VALUE) { | |
| 450 _PR_MD_MAP_OPEN_ERROR(GetLastError()); | |
| 451 return -1; | |
| 452 } | |
| 453 | |
| 454 return (PROsfd)file; | |
| 455 } | |
| 456 | |
| 457 PRInt32 | |
| 458 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) | |
| 459 { | |
| 460 PRUint32 bytes; | |
| 461 int rv, err; | |
| 462 | |
| 463 rv = ReadFile((HANDLE)fd->secret->md.osfd, | |
| 464 (LPVOID)buf, | |
| 465 len, | |
| 466 &bytes, | |
| 467 NULL); | |
| 468 | |
| 469 if (rv == 0) | |
| 470 { | |
| 471 err = GetLastError(); | |
| 472 /* ERROR_HANDLE_EOF can only be returned by async io */ | |
| 473 PR_ASSERT(err != ERROR_HANDLE_EOF); | |
| 474 if (err == ERROR_BROKEN_PIPE) | |
| 475 return 0; | |
| 476 else { | |
| 477 _PR_MD_MAP_READ_ERROR(err); | |
| 478 return -1; | |
| 479 } | |
| 480 } | |
| 481 return bytes; | |
| 482 } | |
| 483 | |
| 484 PRInt32 | |
| 485 _PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) | |
| 486 { | |
| 487 PROsfd f = fd->secret->md.osfd; | |
| 488 PRInt32 bytes; | |
| 489 int rv; | |
| 490 | |
| 491 rv = WriteFile((HANDLE)f, | |
| 492 buf, | |
| 493 len, | |
| 494 &bytes, | |
| 495 NULL ); | |
| 496 | |
| 497 if (rv == 0) | |
| 498 { | |
| 499 _PR_MD_MAP_WRITE_ERROR(GetLastError()); | |
| 500 return -1; | |
| 501 } | |
| 502 return bytes; | |
| 503 } /* --- end _PR_MD_WRITE() --- */ | |
| 504 | |
| 505 PROffset32 | |
| 506 _PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) | |
| 507 { | |
| 508 DWORD moveMethod; | |
| 509 PROffset32 rv; | |
| 510 | |
| 511 switch (whence) { | |
| 512 case PR_SEEK_SET: | |
| 513 moveMethod = FILE_BEGIN; | |
| 514 break; | |
| 515 case PR_SEEK_CUR: | |
| 516 moveMethod = FILE_CURRENT; | |
| 517 break; | |
| 518 case PR_SEEK_END: | |
| 519 moveMethod = FILE_END; | |
| 520 break; | |
| 521 default: | |
| 522 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 523 return -1; | |
| 524 } | |
| 525 | |
| 526 rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod); | |
| 527 | |
| 528 /* | |
| 529 * If the lpDistanceToMoveHigh argument (third argument) is | |
| 530 * NULL, SetFilePointer returns 0xffffffff on failure. | |
| 531 */ | |
| 532 if (-1 == rv) { | |
| 533 _PR_MD_MAP_LSEEK_ERROR(GetLastError()); | |
| 534 } | |
| 535 return rv; | |
| 536 } | |
| 537 | |
| 538 PROffset64 | |
| 539 _PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) | |
| 540 { | |
| 541 DWORD moveMethod; | |
| 542 LARGE_INTEGER li; | |
| 543 DWORD err; | |
| 544 | |
| 545 switch (whence) { | |
| 546 case PR_SEEK_SET: | |
| 547 moveMethod = FILE_BEGIN; | |
| 548 break; | |
| 549 case PR_SEEK_CUR: | |
| 550 moveMethod = FILE_CURRENT; | |
| 551 break; | |
| 552 case PR_SEEK_END: | |
| 553 moveMethod = FILE_END; | |
| 554 break; | |
| 555 default: | |
| 556 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 557 return -1; | |
| 558 } | |
| 559 | |
| 560 li.QuadPart = offset; | |
| 561 li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd, | |
| 562 li.LowPart, &li.HighPart, moveMethod); | |
| 563 | |
| 564 if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) { | |
| 565 _PR_MD_MAP_LSEEK_ERROR(err); | |
| 566 li.QuadPart = -1; | |
| 567 } | |
| 568 return li.QuadPart; | |
| 569 } | |
| 570 | |
| 571 /* | |
| 572 * This is documented to succeed on read-only files, but Win32's | |
| 573 * FlushFileBuffers functions fails with "access denied" in such a | |
| 574 * case. So we only signal an error if the error is *not* "access | |
| 575 * denied". | |
| 576 */ | |
| 577 PRInt32 | |
| 578 _PR_MD_FSYNC(PRFileDesc *fd) | |
| 579 { | |
| 580 /* | |
| 581 * From the documentation: | |
| 582 * | |
| 583 * On Windows NT, the function FlushFileBuffers fails if hFile | |
| 584 * is a handle to console output. That is because console | |
| 585 * output is not buffered. The function returns FALSE, and | |
| 586 * GetLastError returns ERROR_INVALID_HANDLE. | |
| 587 * | |
| 588 * On the other hand, on Win95, it returns without error. I cannot | |
| 589 * assume that 0, 1, and 2 are console, because if someone closes | |
| 590 * System.out and then opens a file, they might get file descriptor | |
| 591 * 1. An error on *that* version of 1 should be reported, whereas | |
| 592 * an error on System.out (which was the original 1) should be | |
| 593 * ignored. So I use isatty() to ensure that such an error was due | |
| 594 * to this bogosity, and if it was, I ignore the error. | |
| 595 */ | |
| 596 | |
| 597 BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd); | |
| 598 | |
| 599 if (!ok) { | |
| 600 DWORD err = GetLastError(); | |
| 601 if (err != ERROR_ACCESS_DENIED) { // from winerror.h | |
| 602 _PR_MD_MAP_FSYNC_ERROR(err); | |
| 603 return -1; | |
| 604 } | |
| 605 } | |
| 606 return 0; | |
| 607 } | |
| 608 | |
| 609 PRInt32 | |
| 610 _MD_CloseFile(PROsfd osfd) | |
| 611 { | |
| 612 PRInt32 rv; | |
| 613 | |
| 614 rv = (CloseHandle((HANDLE)osfd))?0:-1; | |
| 615 if (rv == -1) | |
| 616 _PR_MD_MAP_CLOSE_ERROR(GetLastError()); | |
| 617 return rv; | |
| 618 } | |
| 619 | |
| 620 | |
| 621 /* --- DIR IO ------------------------------------------------------------ */ | |
| 622 #define GetFileFromDIR(d) (d)->d_entry.cFileName | |
| 623 #define FileIsHidden(d) ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) | |
| 624 | |
| 625 static void FlipSlashes(char *cp, size_t len) | |
| 626 { | |
| 627 while (len-- > 0) { | |
| 628 if (cp[0] == '/') { | |
| 629 cp[0] = PR_DIRECTORY_SEPARATOR; | |
| 630 } | |
| 631 cp = _mbsinc(cp); | |
| 632 } | |
| 633 } /* end FlipSlashes() */ | |
| 634 | |
| 635 | |
| 636 /* | |
| 637 ** | |
| 638 ** Local implementations of standard Unix RTL functions which are not provided | |
| 639 ** by the VC RTL. | |
| 640 ** | |
| 641 */ | |
| 642 | |
| 643 PRInt32 | |
| 644 _PR_MD_CLOSE_DIR(_MDDir *d) | |
| 645 { | |
| 646 if ( d ) { | |
| 647 if (FindClose(d->d_hdl)) { | |
| 648 d->magic = (PRUint32)-1; | |
| 649 return 0; | |
| 650 } else { | |
| 651 _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); | |
| 652 return -1; | |
| 653 } | |
| 654 } | |
| 655 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 656 return -1; | |
| 657 } | |
| 658 | |
| 659 | |
| 660 PRStatus | |
| 661 _PR_MD_OPEN_DIR(_MDDir *d, const char *name) | |
| 662 { | |
| 663 char filename[ MAX_PATH ]; | |
| 664 size_t len; | |
| 665 | |
| 666 len = strlen(name); | |
| 667 /* Need 5 bytes for \*.* and the trailing null byte. */ | |
| 668 if (len + 5 > MAX_PATH) { | |
| 669 PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); | |
| 670 return PR_FAILURE; | |
| 671 } | |
| 672 strcpy(filename, name); | |
| 673 | |
| 674 /* | |
| 675 * If 'name' ends in a slash or backslash, do not append | |
| 676 * another backslash. | |
| 677 */ | |
| 678 if (IsPrevCharSlash(filename, filename + len)) { | |
| 679 len--; | |
| 680 } | |
| 681 strcpy(&filename[len], "\\*.*"); | |
| 682 FlipSlashes( filename, strlen(filename) ); | |
| 683 | |
| 684 d->d_hdl = FindFirstFileA( filename, &(d->d_entry) ); | |
| 685 if ( d->d_hdl == INVALID_HANDLE_VALUE ) { | |
| 686 _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); | |
| 687 return PR_FAILURE; | |
| 688 } | |
| 689 d->firstEntry = PR_TRUE; | |
| 690 d->magic = _MD_MAGIC_DIR; | |
| 691 return PR_SUCCESS; | |
| 692 } | |
| 693 | |
| 694 char * | |
| 695 _PR_MD_READ_DIR(_MDDir *d, PRIntn flags) | |
| 696 { | |
| 697 PRInt32 err; | |
| 698 BOOL rv; | |
| 699 char *fileName; | |
| 700 | |
| 701 if ( d ) { | |
| 702 while (1) { | |
| 703 if (d->firstEntry) { | |
| 704 d->firstEntry = PR_FALSE; | |
| 705 rv = 1; | |
| 706 } else { | |
| 707 rv = FindNextFileA(d->d_hdl, &(d->d_entry)); | |
| 708 } | |
| 709 if (rv == 0) { | |
| 710 break; | |
| 711 } | |
| 712 fileName = GetFileFromDIR(d); | |
| 713 if ( (flags & PR_SKIP_DOT) && | |
| 714 (fileName[0] == '.') && (fileName[1] == '\0')) | |
| 715 continue; | |
| 716 if ( (flags & PR_SKIP_DOT_DOT) && | |
| 717 (fileName[0] == '.') && (fileName[1] == '.') && | |
| 718 (fileName[2] == '\0')) | |
| 719 continue; | |
| 720 if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) | |
| 721 continue; | |
| 722 return fileName; | |
| 723 } | |
| 724 err = GetLastError(); | |
| 725 PR_ASSERT(NO_ERROR != err); | |
| 726 _PR_MD_MAP_READDIR_ERROR(err); | |
| 727 return NULL; | |
| 728 } | |
| 729 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 730 return NULL; | |
| 731 } | |
| 732 | |
| 733 PRInt32 | |
| 734 _PR_MD_DELETE(const char *name) | |
| 735 { | |
| 736 if (DeleteFileA(name)) { | |
| 737 return 0; | |
| 738 } else { | |
| 739 _PR_MD_MAP_DELETE_ERROR(GetLastError()); | |
| 740 return -1; | |
| 741 } | |
| 742 } | |
| 743 | |
| 744 void | |
| 745 _PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm) | |
| 746 { | |
| 747 PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime)); | |
| 748 CopyMemory(prtm, filetime, sizeof(PRTime)); | |
| 749 #if defined(__MINGW32__) | |
| 750 *prtm = (*prtm - _pr_filetime_offset) / 10LL; | |
| 751 #else | |
| 752 *prtm = (*prtm - _pr_filetime_offset) / 10i64; | |
| 753 #endif | |
| 754 | |
| 755 #ifdef DEBUG | |
| 756 /* Doublecheck our calculation. */ | |
| 757 { | |
| 758 SYSTEMTIME systime; | |
| 759 PRExplodedTime etm; | |
| 760 PRTime cmp; /* for comparison */ | |
| 761 BOOL rv; | |
| 762 | |
| 763 rv = FileTimeToSystemTime(filetime, &systime); | |
| 764 PR_ASSERT(0 != rv); | |
| 765 | |
| 766 /* | |
| 767 * PR_ImplodeTime ignores wday and yday. | |
| 768 */ | |
| 769 etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC; | |
| 770 etm.tm_sec = systime.wSecond; | |
| 771 etm.tm_min = systime.wMinute; | |
| 772 etm.tm_hour = systime.wHour; | |
| 773 etm.tm_mday = systime.wDay; | |
| 774 etm.tm_month = systime.wMonth - 1; | |
| 775 etm.tm_year = systime.wYear; | |
| 776 /* | |
| 777 * It is not well-documented what time zone the FILETIME's | |
| 778 * are in. WIN32_FIND_DATA is documented to be in UTC (GMT). | |
| 779 * But BY_HANDLE_FILE_INFORMATION is unclear about this. | |
| 780 * By our best judgement, we assume that FILETIME is in UTC. | |
| 781 */ | |
| 782 etm.tm_params.tp_gmt_offset = 0; | |
| 783 etm.tm_params.tp_dst_offset = 0; | |
| 784 cmp = PR_ImplodeTime(&etm); | |
| 785 | |
| 786 /* | |
| 787 * SYSTEMTIME is in milliseconds precision, so we convert PRTime's | |
| 788 * microseconds to milliseconds before doing the comparison. | |
| 789 */ | |
| 790 PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC)); | |
| 791 } | |
| 792 #endif /* DEBUG */ | |
| 793 } | |
| 794 | |
| 795 PRInt32 | |
| 796 _PR_MD_STAT(const char *fn, struct stat *info) | |
| 797 { | |
| 798 #ifdef WINCE | |
| 799 // needs work. dft | |
| 800 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
| 801 return -1; | |
| 802 #else | |
| 803 PRInt32 rv; | |
| 804 | |
| 805 rv = _stat(fn, (struct _stat *)info); | |
| 806 if (-1 == rv) { | |
| 807 /* | |
| 808 * Check for MSVC runtime library _stat() bug. | |
| 809 * (It's really a bug in FindFirstFile().) | |
| 810 * If a pathname ends in a backslash or slash, | |
| 811 * e.g., c:\temp\ or c:/temp/, _stat() will fail. | |
| 812 * Note: a pathname ending in a slash (e.g., c:/temp/) | |
| 813 * can be handled by _stat() on NT but not on Win95. | |
| 814 * | |
| 815 * We remove the backslash or slash at the end and | |
| 816 * try again. | |
| 817 */ | |
| 818 | |
| 819 size_t len = strlen(fn); | |
| 820 if (len > 0 && len <= _MAX_PATH | |
| 821 && IsPrevCharSlash(fn, fn + len)) { | |
| 822 char newfn[_MAX_PATH + 1]; | |
| 823 | |
| 824 strcpy(newfn, fn); | |
| 825 newfn[len - 1] = '\0'; | |
| 826 rv = _stat(newfn, (struct _stat *)info); | |
| 827 } | |
| 828 } | |
| 829 | |
| 830 if (-1 == rv) { | |
| 831 _PR_MD_MAP_STAT_ERROR(errno); | |
| 832 } | |
| 833 return rv; | |
| 834 #endif | |
| 835 } | |
| 836 | |
| 837 #define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\') | |
| 838 | |
| 839 static PRBool | |
| 840 IsPrevCharSlash(const char *str, const char *current) | |
| 841 { | |
| 842 const char *prev; | |
| 843 | |
| 844 if (str >= current) | |
| 845 return PR_FALSE; | |
| 846 prev = _mbsdec(str, current); | |
| 847 return (prev == current - 1) && _PR_IS_SLASH(*prev); | |
| 848 } | |
| 849 | |
| 850 /* | |
| 851 * IsRootDirectory -- | |
| 852 * | |
| 853 * Return PR_TRUE if the pathname 'fn' is a valid root directory, | |
| 854 * else return PR_FALSE. The char buffer pointed to by 'fn' must | |
| 855 * be writable. During the execution of this function, the contents | |
| 856 * of the buffer pointed to by 'fn' may be modified, but on return | |
| 857 * the original contents will be restored. 'buflen' is the size of | |
| 858 * the buffer pointed to by 'fn'. | |
| 859 * | |
| 860 * Root directories come in three formats: | |
| 861 * 1. / or \, meaning the root directory of the current drive. | |
| 862 * 2. C:/ or C:\, where C is a drive letter. | |
| 863 * 3. \\<server name>\<share point name>\ or | |
| 864 * \\<server name>\<share point name>, meaning the root directory | |
| 865 * of a UNC (Universal Naming Convention) name. | |
| 866 */ | |
| 867 | |
| 868 static PRBool | |
| 869 IsRootDirectory(char *fn, size_t buflen) | |
| 870 { | |
| 871 char *p; | |
| 872 PRBool slashAdded = PR_FALSE; | |
| 873 PRBool rv = PR_FALSE; | |
| 874 | |
| 875 if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') { | |
| 876 return PR_TRUE; | |
| 877 } | |
| 878 | |
| 879 if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2]) | |
| 880 && fn[3] == '\0') { | |
| 881 rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; | |
| 882 return rv; | |
| 883 } | |
| 884 | |
| 885 /* The UNC root directory */ | |
| 886 | |
| 887 if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) { | |
| 888 /* The 'server' part should have at least one character. */ | |
| 889 p = &fn[2]; | |
| 890 if (*p == '\0' || _PR_IS_SLASH(*p)) { | |
| 891 return PR_FALSE; | |
| 892 } | |
| 893 | |
| 894 /* look for the next slash */ | |
| 895 do { | |
| 896 p = _mbsinc(p); | |
| 897 } while (*p != '\0' && !_PR_IS_SLASH(*p)); | |
| 898 if (*p == '\0') { | |
| 899 return PR_FALSE; | |
| 900 } | |
| 901 | |
| 902 /* The 'share' part should have at least one character. */ | |
| 903 p++; | |
| 904 if (*p == '\0' || _PR_IS_SLASH(*p)) { | |
| 905 return PR_FALSE; | |
| 906 } | |
| 907 | |
| 908 /* look for the final slash */ | |
| 909 do { | |
| 910 p = _mbsinc(p); | |
| 911 } while (*p != '\0' && !_PR_IS_SLASH(*p)); | |
| 912 if (_PR_IS_SLASH(*p) && p[1] != '\0') { | |
| 913 return PR_FALSE; | |
| 914 } | |
| 915 if (*p == '\0') { | |
| 916 /* | |
| 917 * GetDriveType() doesn't work correctly if the | |
| 918 * path is of the form \\server\share, so we add | |
| 919 * a final slash temporarily. | |
| 920 */ | |
| 921 if ((p + 1) < (fn + buflen)) { | |
| 922 *p++ = '\\'; | |
| 923 *p = '\0'; | |
| 924 slashAdded = PR_TRUE; | |
| 925 } else { | |
| 926 return PR_FALSE; /* name too long */ | |
| 927 } | |
| 928 } | |
| 929 rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; | |
| 930 /* restore the 'fn' buffer */ | |
| 931 if (slashAdded) { | |
| 932 *--p = '\0'; | |
| 933 } | |
| 934 } | |
| 935 return rv; | |
| 936 } | |
| 937 | |
| 938 #ifndef WINCE | |
| 939 /* | |
| 940 * InitGetFileInfo -- | |
| 941 * | |
| 942 * Called during IO init. Checks for the existence of the system function | |
| 943 * GetFileAttributeEx, which when available is used in GETFILEINFO calls. | |
| 944 * If the routine exists, then the address of the routine is stored in the | |
| 945 * variable getFileAttributesEx, which will be used to call the routine. | |
| 946 */ | |
| 947 static void InitGetFileInfo(void) | |
| 948 { | |
| 949 HMODULE module; | |
| 950 module = GetModuleHandle("Kernel32.dll"); | |
| 951 if (!module) { | |
| 952 PR_LOG(_pr_io_lm, PR_LOG_DEBUG, | |
| 953 ("InitGetFileInfo: GetModuleHandle() failed: %d", | |
| 954 GetLastError())); | |
| 955 return; | |
| 956 } | |
| 957 | |
| 958 getFileAttributesEx = (GetFileAttributesExFn) | |
| 959 GetProcAddress(module, "GetFileAttributesExA"); | |
| 960 } | |
| 961 | |
| 962 /* | |
| 963 * If GetFileAttributeEx doesn't exist, we call FindFirstFile as a | |
| 964 * fallback. | |
| 965 */ | |
| 966 static BOOL | |
| 967 GetFileAttributesExFB(const char *fn, WIN32_FIND_DATA *findFileData) | |
| 968 { | |
| 969 HANDLE hFindFile; | |
| 970 | |
| 971 /* | |
| 972 * FindFirstFile() expands wildcard characters. So | |
| 973 * we make sure the pathname contains no wildcard. | |
| 974 */ | |
| 975 if (NULL != _mbspbrk(fn, "?*")) { | |
| 976 SetLastError(ERROR_INVALID_NAME); | |
| 977 return FALSE; | |
| 978 } | |
| 979 | |
| 980 hFindFile = FindFirstFile(fn, findFileData); | |
| 981 if (INVALID_HANDLE_VALUE == hFindFile) { | |
| 982 DWORD len; | |
| 983 char *filePart; | |
| 984 char pathbuf[MAX_PATH + 1]; | |
| 985 | |
| 986 /* | |
| 987 * FindFirstFile() does not work correctly on root directories. | |
| 988 * It also doesn't work correctly on a pathname that ends in a | |
| 989 * slash. So we first check to see if the pathname specifies a | |
| 990 * root directory. If not, and if the pathname ends in a slash, | |
| 991 * we remove the final slash and try again. | |
| 992 */ | |
| 993 | |
| 994 /* | |
| 995 * If the pathname does not contain ., \, and /, it cannot be | |
| 996 * a root directory or a pathname that ends in a slash. | |
| 997 */ | |
| 998 if (NULL == _mbspbrk(fn, ".\\/")) { | |
| 999 return FALSE; | |
| 1000 } | |
| 1001 len = GetFullPathName(fn, sizeof(pathbuf), pathbuf, | |
| 1002 &filePart); | |
| 1003 if (0 == len) { | |
| 1004 return FALSE; | |
| 1005 } | |
| 1006 if (len > sizeof(pathbuf)) { | |
| 1007 SetLastError(ERROR_FILENAME_EXCED_RANGE); | |
| 1008 return FALSE; | |
| 1009 } | |
| 1010 if (IsRootDirectory(pathbuf, sizeof(pathbuf))) { | |
| 1011 findFileData->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; | |
| 1012 /* The file size doesn't have a meaning for directories. */ | |
| 1013 findFileData->nFileSizeHigh = 0; | |
| 1014 findFileData->nFileSizeLow = 0; | |
| 1015 /* | |
| 1016 * For a directory, these timestamps all specify when the | |
| 1017 * directory is created. The creation time doesn't make | |
| 1018 * sense for root directories, so we set it to (NSPR) time 0. | |
| 1019 */ | |
| 1020 memcpy(&findFileData->ftCreationTime, &_pr_filetime_offset, 8); | |
| 1021 findFileData->ftLastAccessTime = findFileData->ftCreationTime; | |
| 1022 findFileData->ftLastWriteTime = findFileData->ftCreationTime; | |
| 1023 return TRUE; | |
| 1024 } | |
| 1025 if (!IsPrevCharSlash(pathbuf, pathbuf + len)) { | |
| 1026 return FALSE; | |
| 1027 } else { | |
| 1028 pathbuf[len - 1] = '\0'; | |
| 1029 hFindFile = FindFirstFile(pathbuf, findFileData); | |
| 1030 if (INVALID_HANDLE_VALUE == hFindFile) { | |
| 1031 return FALSE; | |
| 1032 } | |
| 1033 } | |
| 1034 } | |
| 1035 | |
| 1036 FindClose(hFindFile); | |
| 1037 return TRUE; | |
| 1038 } | |
| 1039 #endif | |
| 1040 | |
| 1041 PRInt32 | |
| 1042 _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) | |
| 1043 { | |
| 1044 #ifdef WINCE | |
| 1045 WIN32_FILE_ATTRIBUTE_DATA findFileData; | |
| 1046 #else | |
| 1047 WIN32_FIND_DATA findFileData; | |
| 1048 #endif | |
| 1049 BOOL rv; | |
| 1050 | |
| 1051 if (NULL == fn || '\0' == *fn) { | |
| 1052 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 1053 return -1; | |
| 1054 } | |
| 1055 | |
| 1056 #ifdef WINCE | |
| 1057 rv = GetFileAttributesExA(fn, GetFileExInfoStandard, &findFileData); | |
| 1058 #else | |
| 1059 /* GetFileAttributesEx is supported on Win 2K and up. */ | |
| 1060 if (getFileAttributesEx) { | |
| 1061 rv = getFileAttributesEx(fn, GetFileExInfoStandard, &findFileData); | |
| 1062 } else { | |
| 1063 rv = GetFileAttributesExFB(fn, &findFileData); | |
| 1064 } | |
| 1065 #endif | |
| 1066 if (!rv) { | |
| 1067 _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); | |
| 1068 return -1; | |
| 1069 } | |
| 1070 | |
| 1071 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | |
| 1072 info->type = PR_FILE_DIRECTORY; | |
| 1073 } else { | |
| 1074 info->type = PR_FILE_FILE; | |
| 1075 } | |
| 1076 | |
| 1077 info->size = findFileData.nFileSizeHigh; | |
| 1078 info->size = (info->size << 32) + findFileData.nFileSizeLow; | |
| 1079 | |
| 1080 _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); | |
| 1081 | |
| 1082 if (0 == findFileData.ftCreationTime.dwLowDateTime && | |
| 1083 0 == findFileData.ftCreationTime.dwHighDateTime) { | |
| 1084 info->creationTime = info->modifyTime; | |
| 1085 } else { | |
| 1086 _PR_FileTimeToPRTime(&findFileData.ftCreationTime, | |
| 1087 &info->creationTime); | |
| 1088 } | |
| 1089 | |
| 1090 return 0; | |
| 1091 } | |
| 1092 | |
| 1093 PRInt32 | |
| 1094 _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) | |
| 1095 { | |
| 1096 PRFileInfo64 info64; | |
| 1097 PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64); | |
| 1098 if (0 == rv) | |
| 1099 { | |
| 1100 info->type = info64.type; | |
| 1101 info->size = (PRUint32) info64.size; | |
| 1102 info->modifyTime = info64.modifyTime; | |
| 1103 info->creationTime = info64.creationTime; | |
| 1104 } | |
| 1105 return rv; | |
| 1106 } | |
| 1107 | |
| 1108 PRInt32 | |
| 1109 _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) | |
| 1110 { | |
| 1111 int rv; | |
| 1112 | |
| 1113 BY_HANDLE_FILE_INFORMATION hinfo; | |
| 1114 | |
| 1115 rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo); | |
| 1116 if (rv == FALSE) { | |
| 1117 _PR_MD_MAP_FSTAT_ERROR(GetLastError()); | |
| 1118 return -1; | |
| 1119 } | |
| 1120 | |
| 1121 if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |
| 1122 info->type = PR_FILE_DIRECTORY; | |
| 1123 else | |
| 1124 info->type = PR_FILE_FILE; | |
| 1125 | |
| 1126 info->size = hinfo.nFileSizeHigh; | |
| 1127 info->size = (info->size << 32) + hinfo.nFileSizeLow; | |
| 1128 | |
| 1129 _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) ); | |
| 1130 _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) ); | |
| 1131 | |
| 1132 return 0; | |
| 1133 } | |
| 1134 | |
| 1135 PRInt32 | |
| 1136 _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) | |
| 1137 { | |
| 1138 PRFileInfo64 info64; | |
| 1139 int rv = _PR_MD_GETOPENFILEINFO64(fd, &info64); | |
| 1140 if (0 == rv) | |
| 1141 { | |
| 1142 info->type = info64.type; | |
| 1143 info->modifyTime = info64.modifyTime; | |
| 1144 info->creationTime = info64.creationTime; | |
| 1145 LL_L2I(info->size, info64.size); | |
| 1146 } | |
| 1147 return rv; | |
| 1148 } | |
| 1149 | |
| 1150 PRStatus | |
| 1151 _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) | |
| 1152 { | |
| 1153 #ifdef WINCE | |
| 1154 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
| 1155 return PR_FAILURE; | |
| 1156 #else | |
| 1157 BOOL rv; | |
| 1158 | |
| 1159 /* | |
| 1160 * The SetHandleInformation function fails with the | |
| 1161 * ERROR_CALL_NOT_IMPLEMENTED error on Win95. | |
| 1162 */ | |
| 1163 rv = SetHandleInformation( | |
| 1164 (HANDLE)fd->secret->md.osfd, | |
| 1165 HANDLE_FLAG_INHERIT, | |
| 1166 inheritable ? HANDLE_FLAG_INHERIT : 0); | |
| 1167 if (0 == rv) { | |
| 1168 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 1169 return PR_FAILURE; | |
| 1170 } | |
| 1171 return PR_SUCCESS; | |
| 1172 #endif | |
| 1173 } | |
| 1174 | |
| 1175 void | |
| 1176 _PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) | |
| 1177 { | |
| 1178 if (imported) { | |
| 1179 fd->secret->inheritable = _PR_TRI_UNKNOWN; | |
| 1180 } else { | |
| 1181 fd->secret->inheritable = _PR_TRI_FALSE; | |
| 1182 } | |
| 1183 } | |
| 1184 | |
| 1185 void | |
| 1186 _PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) | |
| 1187 { | |
| 1188 #ifdef WINCE | |
| 1189 fd->secret->inheritable = _PR_TRI_FALSE; | |
| 1190 #else | |
| 1191 DWORD flags; | |
| 1192 | |
| 1193 PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); | |
| 1194 if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) { | |
| 1195 if (flags & HANDLE_FLAG_INHERIT) { | |
| 1196 fd->secret->inheritable = _PR_TRI_TRUE; | |
| 1197 } else { | |
| 1198 fd->secret->inheritable = _PR_TRI_FALSE; | |
| 1199 } | |
| 1200 } | |
| 1201 #endif | |
| 1202 } | |
| 1203 | |
| 1204 PRInt32 | |
| 1205 _PR_MD_RENAME(const char *from, const char *to) | |
| 1206 { | |
| 1207 /* Does this work with dot-relative pathnames? */ | |
| 1208 if (MoveFileA(from, to)) { | |
| 1209 return 0; | |
| 1210 } else { | |
| 1211 _PR_MD_MAP_RENAME_ERROR(GetLastError()); | |
| 1212 return -1; | |
| 1213 } | |
| 1214 } | |
| 1215 | |
| 1216 PRInt32 | |
| 1217 _PR_MD_ACCESS(const char *name, PRAccessHow how) | |
| 1218 { | |
| 1219 #ifdef WINCE | |
| 1220 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
| 1221 return -1; | |
| 1222 #else | |
| 1223 PRInt32 rv; | |
| 1224 switch (how) { | |
| 1225 case PR_ACCESS_WRITE_OK: | |
| 1226 rv = _access(name, 02); | |
| 1227 break; | |
| 1228 case PR_ACCESS_READ_OK: | |
| 1229 rv = _access(name, 04); | |
| 1230 break; | |
| 1231 case PR_ACCESS_EXISTS: | |
| 1232 return _access(name, 00); | |
| 1233 break; | |
| 1234 default: | |
| 1235 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 1236 return -1; | |
| 1237 } | |
| 1238 if (rv < 0) | |
| 1239 _PR_MD_MAP_ACCESS_ERROR(errno); | |
| 1240 return rv; | |
| 1241 #endif | |
| 1242 } | |
| 1243 | |
| 1244 PRInt32 | |
| 1245 _PR_MD_MKDIR(const char *name, PRIntn mode) | |
| 1246 { | |
| 1247 /* XXXMB - how to translate the "mode"??? */ | |
| 1248 if (CreateDirectoryA(name, NULL)) { | |
| 1249 return 0; | |
| 1250 } else { | |
| 1251 _PR_MD_MAP_MKDIR_ERROR(GetLastError()); | |
| 1252 return -1; | |
| 1253 } | |
| 1254 } | |
| 1255 | |
| 1256 PRInt32 | |
| 1257 _PR_MD_MAKE_DIR(const char *name, PRIntn mode) | |
| 1258 { | |
| 1259 BOOL rv; | |
| 1260 SECURITY_ATTRIBUTES sa; | |
| 1261 LPSECURITY_ATTRIBUTES lpSA = NULL; | |
| 1262 PSECURITY_DESCRIPTOR pSD = NULL; | |
| 1263 PACL pACL = NULL; | |
| 1264 | |
| 1265 if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable, | |
| 1266 &pSD, &pACL) == PR_SUCCESS) { | |
| 1267 sa.nLength = sizeof(sa); | |
| 1268 sa.lpSecurityDescriptor = pSD; | |
| 1269 sa.bInheritHandle = FALSE; | |
| 1270 lpSA = &sa; | |
| 1271 } | |
| 1272 rv = CreateDirectoryA(name, lpSA); | |
| 1273 if (lpSA != NULL) { | |
| 1274 _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); | |
| 1275 } | |
| 1276 if (rv) { | |
| 1277 return 0; | |
| 1278 } else { | |
| 1279 _PR_MD_MAP_MKDIR_ERROR(GetLastError()); | |
| 1280 return -1; | |
| 1281 } | |
| 1282 } | |
| 1283 | |
| 1284 PRInt32 | |
| 1285 _PR_MD_RMDIR(const char *name) | |
| 1286 { | |
| 1287 if (RemoveDirectoryA(name)) { | |
| 1288 return 0; | |
| 1289 } else { | |
| 1290 _PR_MD_MAP_RMDIR_ERROR(GetLastError()); | |
| 1291 return -1; | |
| 1292 } | |
| 1293 } | |
| 1294 | |
| 1295 PRStatus | |
| 1296 _PR_MD_LOCKFILE(PROsfd f) | |
| 1297 { | |
| 1298 PRStatus rc = PR_SUCCESS; | |
| 1299 DWORD rv; | |
| 1300 | |
| 1301 rv = LockFile( (HANDLE)f, | |
| 1302 0l, 0l, | |
| 1303 0x0l, 0xffffffffl ); | |
| 1304 if ( rv == 0 ) { | |
| 1305 DWORD rc = GetLastError(); | |
| 1306 PR_LOG( _pr_io_lm, PR_LOG_ERROR, | |
| 1307 ("_PR_MD_LOCKFILE() failed. Error: %d", rc )); | |
| 1308 rc = PR_FAILURE; | |
| 1309 } | |
| 1310 | |
| 1311 return rc; | |
| 1312 } /* end _PR_MD_LOCKFILE() */ | |
| 1313 | |
| 1314 PRStatus | |
| 1315 _PR_MD_TLOCKFILE(PROsfd f) | |
| 1316 { | |
| 1317 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); | |
| 1318 return PR_FAILURE; | |
| 1319 } /* end _PR_MD_TLOCKFILE() */ | |
| 1320 | |
| 1321 | |
| 1322 PRStatus | |
| 1323 _PR_MD_UNLOCKFILE(PROsfd f) | |
| 1324 { | |
| 1325 PRInt32 rv; | |
| 1326 | |
| 1327 rv = UnlockFile( (HANDLE) f, | |
| 1328 0l, 0l, | |
| 1329 0x0l, 0xffffffffl ); | |
| 1330 | |
| 1331 if ( rv ) | |
| 1332 { | |
| 1333 return PR_SUCCESS; | |
| 1334 } | |
| 1335 else | |
| 1336 { | |
| 1337 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 1338 return PR_FAILURE; | |
| 1339 } | |
| 1340 } /* end _PR_MD_UNLOCKFILE() */ | |
| 1341 | |
| 1342 PRInt32 | |
| 1343 _PR_MD_PIPEAVAILABLE(PRFileDesc *fd) | |
| 1344 { | |
| 1345 if (NULL == fd) | |
| 1346 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); | |
| 1347 else | |
| 1348 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
| 1349 return -1; | |
| 1350 } | |
| 1351 | |
| 1352 #ifdef MOZ_UNICODE | |
| 1353 | |
| 1354 typedef HANDLE (WINAPI *CreateFileWFn) (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIB
UTES, DWORD, DWORD, HANDLE); | |
| 1355 static CreateFileWFn createFileW = CreateFileW; | |
| 1356 typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW); | |
| 1357 static FindFirstFileWFn findFirstFileW = FindFirstFileW; | |
| 1358 typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW); | |
| 1359 static FindNextFileWFn findNextFileW = FindNextFileW; | |
| 1360 typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *); | |
| 1361 static GetFullPathNameWFn getFullPathNameW = GetFullPathNameW; | |
| 1362 typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR); | |
| 1363 static GetDriveTypeWFn getDriveTypeW = GetDriveTypeW; | |
| 1364 | |
| 1365 #endif /* MOZ_UNICODE */ | |
| 1366 | |
| 1367 PRBool _pr_useUnicode = PR_FALSE; | |
| 1368 | |
| 1369 static void InitUnicodeSupport(void) | |
| 1370 { | |
| 1371 #ifdef WINCE | |
| 1372 /* The A functions don't even exist in Windows Mobile. */ | |
| 1373 _pr_useUnicode = PR_TRUE; | |
| 1374 #else | |
| 1375 /* | |
| 1376 * The W functions exist on Win9x as stubs that fail with the | |
| 1377 * ERROR_CALL_NOT_IMPLEMENTED error. We plan to emulate the | |
| 1378 * MSLU W functions on Win9x in the future. | |
| 1379 */ | |
| 1380 | |
| 1381 /* Find out if we are running on a Unicode enabled version of Windows */ | |
| 1382 OSVERSIONINFOA osvi = {0}; | |
| 1383 | |
| 1384 osvi.dwOSVersionInfoSize = sizeof(osvi); | |
| 1385 if (GetVersionExA(&osvi)) { | |
| 1386 _pr_useUnicode = (osvi.dwPlatformId >= VER_PLATFORM_WIN32_NT); | |
| 1387 } else { | |
| 1388 _pr_useUnicode = PR_FALSE; | |
| 1389 } | |
| 1390 #ifdef DEBUG | |
| 1391 /* | |
| 1392 * In debug builds, allow explicit use of ANSI methods to simulate | |
| 1393 * a Win9x environment for testing purposes. | |
| 1394 */ | |
| 1395 if (getenv("WINAPI_USE_ANSI")) | |
| 1396 _pr_useUnicode = PR_FALSE; | |
| 1397 #endif | |
| 1398 #endif | |
| 1399 } | |
| 1400 | |
| 1401 #ifdef MOZ_UNICODE | |
| 1402 | |
| 1403 /* ================ UTF16 Interfaces ================================ */ | |
| 1404 static void FlipSlashesW(PRUnichar *cp, size_t len) | |
| 1405 { | |
| 1406 while (len-- > 0) { | |
| 1407 if (cp[0] == L'/') { | |
| 1408 cp[0] = L'\\'; | |
| 1409 } | |
| 1410 cp++; | |
| 1411 } | |
| 1412 } /* end FlipSlashesW() */ | |
| 1413 | |
| 1414 PROsfd | |
| 1415 _PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, int mode) | |
| 1416 { | |
| 1417 HANDLE file; | |
| 1418 PRInt32 access = 0; | |
| 1419 PRInt32 flags = 0; | |
| 1420 PRInt32 flag6 = 0; | |
| 1421 SECURITY_ATTRIBUTES sa; | |
| 1422 LPSECURITY_ATTRIBUTES lpSA = NULL; | |
| 1423 PSECURITY_DESCRIPTOR pSD = NULL; | |
| 1424 PACL pACL = NULL; | |
| 1425 | |
| 1426 if (osflags & PR_CREATE_FILE) { | |
| 1427 if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, | |
| 1428 &pSD, &pACL) == PR_SUCCESS) { | |
| 1429 sa.nLength = sizeof(sa); | |
| 1430 sa.lpSecurityDescriptor = pSD; | |
| 1431 sa.bInheritHandle = FALSE; | |
| 1432 lpSA = &sa; | |
| 1433 } | |
| 1434 } | |
| 1435 | |
| 1436 if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; | |
| 1437 | |
| 1438 if (osflags & PR_RDONLY || osflags & PR_RDWR) | |
| 1439 access |= GENERIC_READ; | |
| 1440 if (osflags & PR_WRONLY || osflags & PR_RDWR) | |
| 1441 access |= GENERIC_WRITE; | |
| 1442 | |
| 1443 if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) | |
| 1444 flags = CREATE_NEW; | |
| 1445 else if (osflags & PR_CREATE_FILE) { | |
| 1446 if (osflags & PR_TRUNCATE) | |
| 1447 flags = CREATE_ALWAYS; | |
| 1448 else | |
| 1449 flags = OPEN_ALWAYS; | |
| 1450 } else { | |
| 1451 if (osflags & PR_TRUNCATE) | |
| 1452 flags = TRUNCATE_EXISTING; | |
| 1453 else | |
| 1454 flags = OPEN_EXISTING; | |
| 1455 } | |
| 1456 | |
| 1457 file = createFileW(name, | |
| 1458 access, | |
| 1459 FILE_SHARE_READ|FILE_SHARE_WRITE, | |
| 1460 lpSA, | |
| 1461 flags, | |
| 1462 flag6, | |
| 1463 NULL); | |
| 1464 if (lpSA != NULL) { | |
| 1465 _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); | |
| 1466 } | |
| 1467 if (file == INVALID_HANDLE_VALUE) { | |
| 1468 _PR_MD_MAP_OPEN_ERROR(GetLastError()); | |
| 1469 return -1; | |
| 1470 } | |
| 1471 | |
| 1472 return (PROsfd)file; | |
| 1473 } | |
| 1474 | |
| 1475 PRStatus | |
| 1476 _PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name) | |
| 1477 { | |
| 1478 PRUnichar filename[ MAX_PATH ]; | |
| 1479 int len; | |
| 1480 | |
| 1481 len = wcslen(name); | |
| 1482 /* Need 5 bytes for \*.* and the trailing null byte. */ | |
| 1483 if (len + 5 > MAX_PATH) { | |
| 1484 PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); | |
| 1485 return PR_FAILURE; | |
| 1486 } | |
| 1487 wcscpy(filename, name); | |
| 1488 | |
| 1489 /* | |
| 1490 * If 'name' ends in a slash or backslash, do not append | |
| 1491 * another backslash. | |
| 1492 */ | |
| 1493 if (filename[len - 1] == L'/' || filename[len - 1] == L'\\') { | |
| 1494 len--; | |
| 1495 } | |
| 1496 wcscpy(&filename[len], L"\\*.*"); | |
| 1497 FlipSlashesW( filename, wcslen(filename) ); | |
| 1498 | |
| 1499 d->d_hdl = findFirstFileW( filename, &(d->d_entry) ); | |
| 1500 if ( d->d_hdl == INVALID_HANDLE_VALUE ) { | |
| 1501 _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); | |
| 1502 return PR_FAILURE; | |
| 1503 } | |
| 1504 d->firstEntry = PR_TRUE; | |
| 1505 d->magic = _MD_MAGIC_DIR; | |
| 1506 return PR_SUCCESS; | |
| 1507 } | |
| 1508 | |
| 1509 PRUnichar * | |
| 1510 _PR_MD_READ_DIR_UTF16(_MDDirUTF16 *d, PRIntn flags) | |
| 1511 { | |
| 1512 PRInt32 err; | |
| 1513 BOOL rv; | |
| 1514 PRUnichar *fileName; | |
| 1515 | |
| 1516 if ( d ) { | |
| 1517 while (1) { | |
| 1518 if (d->firstEntry) { | |
| 1519 d->firstEntry = PR_FALSE; | |
| 1520 rv = 1; | |
| 1521 } else { | |
| 1522 rv = findNextFileW(d->d_hdl, &(d->d_entry)); | |
| 1523 } | |
| 1524 if (rv == 0) { | |
| 1525 break; | |
| 1526 } | |
| 1527 fileName = GetFileFromDIR(d); | |
| 1528 if ( (flags & PR_SKIP_DOT) && | |
| 1529 (fileName[0] == L'.') && (fileName[1] == L'\0')) | |
| 1530 continue; | |
| 1531 if ( (flags & PR_SKIP_DOT_DOT) && | |
| 1532 (fileName[0] == L'.') && (fileName[1] == L'.') && | |
| 1533 (fileName[2] == L'\0')) | |
| 1534 continue; | |
| 1535 if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) | |
| 1536 continue; | |
| 1537 return fileName; | |
| 1538 } | |
| 1539 err = GetLastError(); | |
| 1540 PR_ASSERT(NO_ERROR != err); | |
| 1541 _PR_MD_MAP_READDIR_ERROR(err); | |
| 1542 return NULL; | |
| 1543 } | |
| 1544 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 1545 return NULL; | |
| 1546 } | |
| 1547 | |
| 1548 PRInt32 | |
| 1549 _PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *d) | |
| 1550 { | |
| 1551 if ( d ) { | |
| 1552 if (FindClose(d->d_hdl)) { | |
| 1553 d->magic = (PRUint32)-1; | |
| 1554 return 0; | |
| 1555 } else { | |
| 1556 _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); | |
| 1557 return -1; | |
| 1558 } | |
| 1559 } | |
| 1560 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 1561 return -1; | |
| 1562 } | |
| 1563 | |
| 1564 #define _PR_IS_W_SLASH(ch) ((ch) == L'/' || (ch) == L'\\') | |
| 1565 | |
| 1566 /* | |
| 1567 * IsRootDirectoryW -- | |
| 1568 * | |
| 1569 * Return PR_TRUE if the pathname 'fn' is a valid root directory, | |
| 1570 * else return PR_FALSE. The PRUnichar buffer pointed to by 'fn' must | |
| 1571 * be writable. During the execution of this function, the contents | |
| 1572 * of the buffer pointed to by 'fn' may be modified, but on return | |
| 1573 * the original contents will be restored. 'buflen' is the size of | |
| 1574 * the buffer pointed to by 'fn', in PRUnichars. | |
| 1575 * | |
| 1576 * Root directories come in three formats: | |
| 1577 * 1. / or \, meaning the root directory of the current drive. | |
| 1578 * 2. C:/ or C:\, where C is a drive letter. | |
| 1579 * 3. \\<server name>\<share point name>\ or | |
| 1580 * \\<server name>\<share point name>, meaning the root directory | |
| 1581 * of a UNC (Universal Naming Convention) name. | |
| 1582 */ | |
| 1583 | |
| 1584 static PRBool | |
| 1585 IsRootDirectoryW(PRUnichar *fn, size_t buflen) | |
| 1586 { | |
| 1587 PRUnichar *p; | |
| 1588 PRBool slashAdded = PR_FALSE; | |
| 1589 PRBool rv = PR_FALSE; | |
| 1590 | |
| 1591 if (_PR_IS_W_SLASH(fn[0]) && fn[1] == L'\0') { | |
| 1592 return PR_TRUE; | |
| 1593 } | |
| 1594 | |
| 1595 if (iswalpha(fn[0]) && fn[1] == L':' && _PR_IS_W_SLASH(fn[2]) | |
| 1596 && fn[3] == L'\0') { | |
| 1597 rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE; | |
| 1598 return rv; | |
| 1599 } | |
| 1600 | |
| 1601 /* The UNC root directory */ | |
| 1602 | |
| 1603 if (_PR_IS_W_SLASH(fn[0]) && _PR_IS_W_SLASH(fn[1])) { | |
| 1604 /* The 'server' part should have at least one character. */ | |
| 1605 p = &fn[2]; | |
| 1606 if (*p == L'\0' || _PR_IS_W_SLASH(*p)) { | |
| 1607 return PR_FALSE; | |
| 1608 } | |
| 1609 | |
| 1610 /* look for the next slash */ | |
| 1611 do { | |
| 1612 p++; | |
| 1613 } while (*p != L'\0' && !_PR_IS_W_SLASH(*p)); | |
| 1614 if (*p == L'\0') { | |
| 1615 return PR_FALSE; | |
| 1616 } | |
| 1617 | |
| 1618 /* The 'share' part should have at least one character. */ | |
| 1619 p++; | |
| 1620 if (*p == L'\0' || _PR_IS_W_SLASH(*p)) { | |
| 1621 return PR_FALSE; | |
| 1622 } | |
| 1623 | |
| 1624 /* look for the final slash */ | |
| 1625 do { | |
| 1626 p++; | |
| 1627 } while (*p != L'\0' && !_PR_IS_W_SLASH(*p)); | |
| 1628 if (_PR_IS_W_SLASH(*p) && p[1] != L'\0') { | |
| 1629 return PR_FALSE; | |
| 1630 } | |
| 1631 if (*p == L'\0') { | |
| 1632 /* | |
| 1633 * GetDriveType() doesn't work correctly if the | |
| 1634 * path is of the form \\server\share, so we add | |
| 1635 * a final slash temporarily. | |
| 1636 */ | |
| 1637 if ((p + 1) < (fn + buflen)) { | |
| 1638 *p++ = L'\\'; | |
| 1639 *p = L'\0'; | |
| 1640 slashAdded = PR_TRUE; | |
| 1641 } else { | |
| 1642 return PR_FALSE; /* name too long */ | |
| 1643 } | |
| 1644 } | |
| 1645 rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE; | |
| 1646 /* restore the 'fn' buffer */ | |
| 1647 if (slashAdded) { | |
| 1648 *--p = L'\0'; | |
| 1649 } | |
| 1650 } | |
| 1651 return rv; | |
| 1652 } | |
| 1653 | |
| 1654 PRInt32 | |
| 1655 _PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info) | |
| 1656 { | |
| 1657 HANDLE hFindFile; | |
| 1658 WIN32_FIND_DATAW findFileData; | |
| 1659 PRUnichar pathbuf[MAX_PATH + 1]; | |
| 1660 | |
| 1661 if (NULL == fn || L'\0' == *fn) { | |
| 1662 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 1663 return -1; | |
| 1664 } | |
| 1665 | |
| 1666 /* | |
| 1667 * FindFirstFile() expands wildcard characters. So | |
| 1668 * we make sure the pathname contains no wildcard. | |
| 1669 */ | |
| 1670 if (NULL != wcspbrk(fn, L"?*")) { | |
| 1671 PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0); | |
| 1672 return -1; | |
| 1673 } | |
| 1674 | |
| 1675 hFindFile = findFirstFileW(fn, &findFileData); | |
| 1676 if (INVALID_HANDLE_VALUE == hFindFile) { | |
| 1677 DWORD len; | |
| 1678 PRUnichar *filePart; | |
| 1679 | |
| 1680 /* | |
| 1681 * FindFirstFile() does not work correctly on root directories. | |
| 1682 * It also doesn't work correctly on a pathname that ends in a | |
| 1683 * slash. So we first check to see if the pathname specifies a | |
| 1684 * root directory. If not, and if the pathname ends in a slash, | |
| 1685 * we remove the final slash and try again. | |
| 1686 */ | |
| 1687 | |
| 1688 /* | |
| 1689 * If the pathname does not contain ., \, and /, it cannot be | |
| 1690 * a root directory or a pathname that ends in a slash. | |
| 1691 */ | |
| 1692 if (NULL == wcspbrk(fn, L".\\/")) { | |
| 1693 _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); | |
| 1694 return -1; | |
| 1695 } | |
| 1696 len = getFullPathNameW(fn, sizeof(pathbuf)/sizeof(pathbuf[0]), pathbuf, | |
| 1697 &filePart); | |
| 1698 if (0 == len) { | |
| 1699 _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); | |
| 1700 return -1; | |
| 1701 } | |
| 1702 if (len > sizeof(pathbuf)/sizeof(pathbuf[0])) { | |
| 1703 PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); | |
| 1704 return -1; | |
| 1705 } | |
| 1706 if (IsRootDirectoryW(pathbuf, sizeof(pathbuf)/sizeof(pathbuf[0]))) { | |
| 1707 info->type = PR_FILE_DIRECTORY; | |
| 1708 info->size = 0; | |
| 1709 /* | |
| 1710 * These timestamps don't make sense for root directories. | |
| 1711 */ | |
| 1712 info->modifyTime = 0; | |
| 1713 info->creationTime = 0; | |
| 1714 return 0; | |
| 1715 } | |
| 1716 if (!_PR_IS_W_SLASH(pathbuf[len - 1])) { | |
| 1717 _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); | |
| 1718 return -1; | |
| 1719 } else { | |
| 1720 pathbuf[len - 1] = L'\0'; | |
| 1721 hFindFile = findFirstFileW(pathbuf, &findFileData); | |
| 1722 if (INVALID_HANDLE_VALUE == hFindFile) { | |
| 1723 _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); | |
| 1724 return -1; | |
| 1725 } | |
| 1726 } | |
| 1727 } | |
| 1728 | |
| 1729 FindClose(hFindFile); | |
| 1730 | |
| 1731 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | |
| 1732 info->type = PR_FILE_DIRECTORY; | |
| 1733 } else { | |
| 1734 info->type = PR_FILE_FILE; | |
| 1735 } | |
| 1736 | |
| 1737 info->size = findFileData.nFileSizeHigh; | |
| 1738 info->size = (info->size << 32) + findFileData.nFileSizeLow; | |
| 1739 | |
| 1740 _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); | |
| 1741 | |
| 1742 if (0 == findFileData.ftCreationTime.dwLowDateTime && | |
| 1743 0 == findFileData.ftCreationTime.dwHighDateTime) { | |
| 1744 info->creationTime = info->modifyTime; | |
| 1745 } else { | |
| 1746 _PR_FileTimeToPRTime(&findFileData.ftCreationTime, | |
| 1747 &info->creationTime); | |
| 1748 } | |
| 1749 | |
| 1750 return 0; | |
| 1751 } | |
| 1752 /* ================ end of UTF16 Interfaces ================================ */ | |
| 1753 #endif /* MOZ_UNICODE */ | |
| OLD | NEW |