Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(756)

Side by Side Diff: mozilla/nsprpub/pr/src/md/windows/w95io.c

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

Powered by Google App Engine
This is Rietveld 408576698