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