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 */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)