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 |