1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
15
* The Initial Developer of the Original Code is Netscape
16
* Communications Corporation. Portions created by Netscape are
17
* Copyright (C) 1998-2000 Netscape Communications Corporation. All
22
* Alternatively, the contents of this file may be used under the
23
* terms of the GNU General Public License Version 2 or later (the
24
* "GPL"), in which case the provisions of the GPL are applicable
25
* instead of those above. If you wish to allow use of your
26
* version of this file only under the terms of the GPL and not to
27
* allow others to use your version of this file under the MPL,
28
* indicate your decision by deleting the provisions above and
29
* replace them with the notice and other provisions required by
30
* the GPL. If you do not delete the provisions above, a recipient
31
* may use your version of this file under either the MPL or the
35
/* Windows 95 IO module
37
* Assumes synchronous I/O.
46
#endif /* MOZ_UNICODE */
49
struct _MDLock _pr_ioq_lock;
52
* NSPR-to-NT access right mapping table for files.
54
static DWORD fileAccessTable[] = {
61
* NSPR-to-NT access right mapping table for directories.
63
static DWORD dirAccessTable[] = {
65
FILE_GENERIC_WRITE|FILE_DELETE_CHILD,
70
* The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
71
* We store the value in a PRTime variable for convenience.
72
* This constant is used by _PR_FileTimeToPRTime().
74
#if defined(__MINGW32__)
75
static const PRTime _pr_filetime_offset = 116444736000000000LL;
77
static const PRTime _pr_filetime_offset = 116444736000000000i64;
81
static void InitUnicodeSupport(void);
87
WORD WSAVersion = 0x0101;
91
err = WSAStartup( WSAVersion, &WSAData );
95
/* Doublecheck _pr_filetime_offset's hard-coded value is correct. */
104
systime.wYear = 1970;
106
/* wDayOfWeek is ignored */
111
systime.wMilliseconds = 0;
113
rv = SystemTimeToFileTime(&systime, &filetime.ft);
115
PR_ASSERT(filetime.prt == _pr_filetime_offset);
122
InitUnicodeSupport();
127
_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
131
PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
132
INFINITE : PR_IntervalToMilliseconds(ticks);
133
rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
140
_PR_THREAD_LOCK(thread);
141
if (thread->state == _PR_IO_WAIT) {
144
if (thread->wait.cvar != NULL) {
145
thread->wait.cvar = NULL;
146
_PR_THREAD_UNLOCK(thread);
148
/* The CVAR was notified just as the timeout
149
* occurred. This led to us being notified twice.
150
* call WaitForSingleObject() to clear the semaphore.
152
_PR_THREAD_UNLOCK(thread);
153
rv = WaitForSingleObject(thread->md.blocked_sema, 0);
154
PR_ASSERT(rv == WAIT_OBJECT_0);
165
_PR_MD_WAKEUP_WAITER(PRThread *thread)
167
if ( _PR_IS_NATIVE_THREAD(thread) )
169
if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE)
177
/* --- FILE IO ----------------------------------------------------------- */
179
* _PR_MD_OPEN() -- Open a file
181
* returns: a fileHandle
183
* The NSPR open flags (osflags) are translated into flags for Win95
185
* Mode seems to be passed in as a unix style file permissions argument
186
* as in 0666, in the case of opening the logFile.
190
_PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
197
if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
199
if (osflags & PR_RDONLY || osflags & PR_RDWR)
200
access |= GENERIC_READ;
201
if (osflags & PR_WRONLY || osflags & PR_RDWR)
202
access |= GENERIC_WRITE;
204
if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
206
else if (osflags & PR_CREATE_FILE) {
207
if (osflags & PR_TRUNCATE)
208
flags = CREATE_ALWAYS;
212
if (osflags & PR_TRUNCATE)
213
flags = TRUNCATE_EXISTING;
215
flags = OPEN_EXISTING;
218
file = CreateFile(name,
220
FILE_SHARE_READ|FILE_SHARE_WRITE,
225
if (file == INVALID_HANDLE_VALUE) {
226
_PR_MD_MAP_OPEN_ERROR(GetLastError());
230
return (PRInt32)file;
234
_PR_MD_OPEN_FILE(const char *name, PRIntn osflags, int mode)
240
SECURITY_ATTRIBUTES sa;
241
LPSECURITY_ATTRIBUTES lpSA = NULL;
242
PSECURITY_DESCRIPTOR pSD = NULL;
245
if (osflags & PR_CREATE_FILE) {
246
if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
247
&pSD, &pACL) == PR_SUCCESS) {
248
sa.nLength = sizeof(sa);
249
sa.lpSecurityDescriptor = pSD;
250
sa.bInheritHandle = FALSE;
255
if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
257
if (osflags & PR_RDONLY || osflags & PR_RDWR)
258
access |= GENERIC_READ;
259
if (osflags & PR_WRONLY || osflags & PR_RDWR)
260
access |= GENERIC_WRITE;
262
if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
264
else if (osflags & PR_CREATE_FILE) {
265
if (osflags & PR_TRUNCATE)
266
flags = CREATE_ALWAYS;
270
if (osflags & PR_TRUNCATE)
271
flags = TRUNCATE_EXISTING;
273
flags = OPEN_EXISTING;
276
file = CreateFile(name,
278
FILE_SHARE_READ|FILE_SHARE_WRITE,
284
_PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
286
if (file == INVALID_HANDLE_VALUE) {
287
_PR_MD_MAP_OPEN_ERROR(GetLastError());
291
return (PRInt32)file;
295
_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
300
rv = ReadFile((HANDLE)fd->secret->md.osfd,
308
err = GetLastError();
309
/* ERROR_HANDLE_EOF can only be returned by async io */
310
PR_ASSERT(err != ERROR_HANDLE_EOF);
311
if (err == ERROR_BROKEN_PIPE)
314
_PR_MD_MAP_READ_ERROR(err);
322
_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
324
PRInt32 f = fd->secret->md.osfd;
327
PRThread *me = _PR_MD_CURRENT_THREAD();
329
rv = WriteFile((HANDLE)f,
337
_PR_MD_MAP_WRITE_ERROR(GetLastError());
341
} /* --- end _PR_MD_WRITE() --- */
344
_PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
351
moveMethod = FILE_BEGIN;
354
moveMethod = FILE_CURRENT;
357
moveMethod = FILE_END;
360
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
364
rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod);
367
* If the lpDistanceToMoveHigh argument (third argument) is
368
* NULL, SetFilePointer returns 0xffffffff on failure.
371
_PR_MD_MAP_LSEEK_ERROR(GetLastError());
377
_PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence)
385
moveMethod = FILE_BEGIN;
388
moveMethod = FILE_CURRENT;
391
moveMethod = FILE_END;
394
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
398
li.QuadPart = offset;
399
li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd,
400
li.LowPart, &li.HighPart, moveMethod);
402
if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) {
403
_PR_MD_MAP_LSEEK_ERROR(err);
410
* This is documented to succeed on read-only files, but Win32's
411
* FlushFileBuffers functions fails with "access denied" in such a
412
* case. So we only signal an error if the error is *not* "access
416
_PR_MD_FSYNC(PRFileDesc *fd)
419
* From the documentation:
421
* On Windows NT, the function FlushFileBuffers fails if hFile
422
* is a handle to console output. That is because console
423
* output is not buffered. The function returns FALSE, and
424
* GetLastError returns ERROR_INVALID_HANDLE.
426
* On the other hand, on Win95, it returns without error. I cannot
427
* assume that 0, 1, and 2 are console, because if someone closes
428
* System.out and then opens a file, they might get file descriptor
429
* 1. An error on *that* version of 1 should be reported, whereas
430
* an error on System.out (which was the original 1) should be
431
* ignored. So I use isatty() to ensure that such an error was due
432
* to this bogosity, and if it was, I ignore the error.
435
BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd);
438
DWORD err = GetLastError();
439
if (err != ERROR_ACCESS_DENIED) { // from winerror.h
440
_PR_MD_MAP_FSYNC_ERROR(err);
448
_MD_CloseFile(PRInt32 osfd)
452
rv = (CloseHandle((HANDLE)osfd))?0:-1;
454
_PR_MD_MAP_CLOSE_ERROR(GetLastError());
459
/* --- DIR IO ------------------------------------------------------------ */
460
#define GetFileFromDIR(d) (d)->d_entry.cFileName
461
#define FileIsHidden(d) ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
463
void FlipSlashes(char *cp, int len)
467
cp[0] = PR_DIRECTORY_SEPARATOR;
471
} /* end FlipSlashes() */
476
** Local implementations of standard Unix RTL functions which are not provided
482
_PR_MD_CLOSE_DIR(_MDDir *d)
485
if (FindClose(d->d_hdl)) {
486
d->magic = (PRUint32)-1;
489
_PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
493
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
499
_PR_MD_OPEN_DIR(_MDDir *d, const char *name)
501
char filename[ MAX_PATH ];
505
/* Need 5 bytes for \*.* and the trailing null byte. */
506
if (len + 5 > MAX_PATH) {
507
PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
510
strcpy(filename, name);
513
* If 'name' ends in a slash or backslash, do not append
516
if (filename[len - 1] == '/' || filename[len - 1] == '\\') {
519
strcpy(&filename[len], "\\*.*");
520
FlipSlashes( filename, strlen(filename) );
522
d->d_hdl = FindFirstFile( filename, &(d->d_entry) );
523
if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
524
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
527
d->firstEntry = PR_TRUE;
528
d->magic = _MD_MAGIC_DIR;
533
_PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
542
d->firstEntry = PR_FALSE;
545
rv = FindNextFile(d->d_hdl, &(d->d_entry));
550
fileName = GetFileFromDIR(d);
551
if ( (flags & PR_SKIP_DOT) &&
552
(fileName[0] == '.') && (fileName[1] == '\0'))
554
if ( (flags & PR_SKIP_DOT_DOT) &&
555
(fileName[0] == '.') && (fileName[1] == '.') &&
556
(fileName[2] == '\0'))
558
if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
562
err = GetLastError();
563
PR_ASSERT(NO_ERROR != err);
564
_PR_MD_MAP_READDIR_ERROR(err);
567
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
572
_PR_MD_DELETE(const char *name)
574
if (DeleteFile(name)) {
577
_PR_MD_MAP_DELETE_ERROR(GetLastError());
583
_PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm)
585
PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
586
CopyMemory(prtm, filetime, sizeof(PRTime));
587
#if defined(__MINGW32__)
588
*prtm = (*prtm - _pr_filetime_offset) / 10LL;
590
*prtm = (*prtm - _pr_filetime_offset) / 10i64;
594
/* Doublecheck our calculation. */
598
PRTime cmp; /* for comparison */
601
rv = FileTimeToSystemTime(filetime, &systime);
605
* PR_ImplodeTime ignores wday and yday.
607
etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC;
608
etm.tm_sec = systime.wSecond;
609
etm.tm_min = systime.wMinute;
610
etm.tm_hour = systime.wHour;
611
etm.tm_mday = systime.wDay;
612
etm.tm_month = systime.wMonth - 1;
613
etm.tm_year = systime.wYear;
615
* It is not well-documented what time zone the FILETIME's
616
* are in. WIN32_FIND_DATA is documented to be in UTC (GMT).
617
* But BY_HANDLE_FILE_INFORMATION is unclear about this.
618
* By our best judgement, we assume that FILETIME is in UTC.
620
etm.tm_params.tp_gmt_offset = 0;
621
etm.tm_params.tp_dst_offset = 0;
622
cmp = PR_ImplodeTime(&etm);
625
* SYSTEMTIME is in milliseconds precision, so we convert PRTime's
626
* microseconds to milliseconds before doing the comparison.
628
PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC));
634
_PR_MD_STAT(const char *fn, struct stat *info)
638
rv = _stat(fn, (struct _stat *)info);
641
* Check for MSVC runtime library _stat() bug.
642
* (It's really a bug in FindFirstFile().)
643
* If a pathname ends in a backslash or slash,
644
* e.g., c:\temp\ or c:/temp/, _stat() will fail.
645
* Note: a pathname ending in a slash (e.g., c:/temp/)
646
* can be handled by _stat() on NT but not on Win95.
648
* We remove the backslash or slash at the end and
652
int len = strlen(fn);
653
if (len > 0 && len <= _MAX_PATH
654
&& (fn[len - 1] == '\\' || fn[len - 1] == '/')) {
655
char newfn[_MAX_PATH + 1];
658
newfn[len - 1] = '\0';
659
rv = _stat(newfn, (struct _stat *)info);
664
_PR_MD_MAP_STAT_ERROR(errno);
669
#define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\')
674
* Return PR_TRUE if the pathname 'fn' is a valid root directory,
675
* else return PR_FALSE. The char buffer pointed to by 'fn' must
676
* be writable. During the execution of this function, the contents
677
* of the buffer pointed to by 'fn' may be modified, but on return
678
* the original contents will be restored. 'buflen' is the size of
679
* the buffer pointed to by 'fn'.
681
* Root directories come in three formats:
682
* 1. / or \, meaning the root directory of the current drive.
683
* 2. C:/ or C:\, where C is a drive letter.
684
* 3. \\<server name>\<share point name>\ or
685
* \\<server name>\<share point name>, meaning the root directory
686
* of a UNC (Universal Naming Convention) name.
690
IsRootDirectory(char *fn, size_t buflen)
693
PRBool slashAdded = PR_FALSE;
694
PRBool rv = PR_FALSE;
696
if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') {
700
if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2])
702
rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
706
/* The UNC root directory */
708
if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) {
709
/* The 'server' part should have at least one character. */
711
if (*p == '\0' || _PR_IS_SLASH(*p)) {
715
/* look for the next slash */
718
} while (*p != '\0' && !_PR_IS_SLASH(*p));
723
/* The 'share' part should have at least one character. */
725
if (*p == '\0' || _PR_IS_SLASH(*p)) {
729
/* look for the final slash */
732
} while (*p != '\0' && !_PR_IS_SLASH(*p));
733
if (_PR_IS_SLASH(*p) && p[1] != '\0') {
738
* GetDriveType() doesn't work correctly if the
739
* path is of the form \\server\share, so we add
740
* a final slash temporarily.
742
if ((p + 1) < (fn + buflen)) {
745
slashAdded = PR_TRUE;
747
return PR_FALSE; /* name too long */
750
rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
751
/* restore the 'fn' buffer */
760
_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
763
WIN32_FIND_DATA findFileData;
764
char pathbuf[MAX_PATH + 1];
766
if (NULL == fn || '\0' == *fn) {
767
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
772
* FindFirstFile() expands wildcard characters. So
773
* we make sure the pathname contains no wildcard.
775
if (NULL != _mbspbrk(fn, "?*")) {
776
PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0);
780
hFindFile = FindFirstFile(fn, &findFileData);
781
if (INVALID_HANDLE_VALUE == hFindFile) {
786
* FindFirstFile() does not work correctly on root directories.
787
* It also doesn't work correctly on a pathname that ends in a
788
* slash. So we first check to see if the pathname specifies a
789
* root directory. If not, and if the pathname ends in a slash,
790
* we remove the final slash and try again.
794
* If the pathname does not contain ., \, and /, it cannot be
795
* a root directory or a pathname that ends in a slash.
797
if (NULL == _mbspbrk(fn, ".\\/")) {
798
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
801
len = GetFullPathName(fn, sizeof(pathbuf), pathbuf,
804
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
807
if (len > sizeof(pathbuf)) {
808
PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
811
if (IsRootDirectory(pathbuf, sizeof(pathbuf))) {
812
info->type = PR_FILE_DIRECTORY;
815
* These timestamps don't make sense for root directories.
817
info->modifyTime = 0;
818
info->creationTime = 0;
821
if (!_PR_IS_SLASH(pathbuf[len - 1])) {
822
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
825
pathbuf[len - 1] = '\0';
826
hFindFile = FindFirstFile(pathbuf, &findFileData);
827
if (INVALID_HANDLE_VALUE == hFindFile) {
828
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
834
FindClose(hFindFile);
836
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
837
info->type = PR_FILE_DIRECTORY;
839
info->type = PR_FILE_FILE;
842
info->size = findFileData.nFileSizeHigh;
843
info->size = (info->size << 32) + findFileData.nFileSizeLow;
845
_PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);
847
if (0 == findFileData.ftCreationTime.dwLowDateTime &&
848
0 == findFileData.ftCreationTime.dwHighDateTime) {
849
info->creationTime = info->modifyTime;
851
_PR_FileTimeToPRTime(&findFileData.ftCreationTime,
852
&info->creationTime);
859
_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
862
PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64);
865
info->type = info64.type;
866
info->size = (PRUint32) info64.size;
867
info->modifyTime = info64.modifyTime;
868
info->creationTime = info64.creationTime;
874
_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
878
BY_HANDLE_FILE_INFORMATION hinfo;
880
rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo);
882
_PR_MD_MAP_FSTAT_ERROR(GetLastError());
886
if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
887
info->type = PR_FILE_DIRECTORY;
889
info->type = PR_FILE_FILE;
891
info->size = hinfo.nFileSizeHigh;
892
info->size = (info->size << 32) + hinfo.nFileSizeLow;
894
_PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) );
895
_PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) );
901
_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
904
int rv = _PR_MD_GETOPENFILEINFO64(fd, &info64);
907
info->type = info64.type;
908
info->modifyTime = info64.modifyTime;
909
info->creationTime = info64.creationTime;
910
LL_L2I(info->size, info64.size);
916
_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable)
921
* The SetHandleInformation function fails with the
922
* ERROR_CALL_NOT_IMPLEMENTED error on Win95.
924
rv = SetHandleInformation(
925
(HANDLE)fd->secret->md.osfd,
927
inheritable ? HANDLE_FLAG_INHERIT : 0);
929
_PR_MD_MAP_DEFAULT_ERROR(GetLastError());
936
_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported)
939
fd->secret->inheritable = _PR_TRI_UNKNOWN;
941
fd->secret->inheritable = _PR_TRI_FALSE;
946
_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd)
950
PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
951
if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) {
952
if (flags & HANDLE_FLAG_INHERIT) {
953
fd->secret->inheritable = _PR_TRI_TRUE;
955
fd->secret->inheritable = _PR_TRI_FALSE;
961
_PR_MD_RENAME(const char *from, const char *to)
963
/* Does this work with dot-relative pathnames? */
964
if (MoveFile(from, to)) {
967
_PR_MD_MAP_RENAME_ERROR(GetLastError());
973
_PR_MD_ACCESS(const char *name, PRAccessHow how)
977
case PR_ACCESS_WRITE_OK:
978
rv = _access(name, 02);
980
case PR_ACCESS_READ_OK:
981
rv = _access(name, 04);
983
case PR_ACCESS_EXISTS:
984
return _access(name, 00);
987
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
991
_PR_MD_MAP_ACCESS_ERROR(errno);
996
_PR_MD_MKDIR(const char *name, PRIntn mode)
998
/* XXXMB - how to translate the "mode"??? */
999
if (CreateDirectory(name, NULL)) {
1002
_PR_MD_MAP_MKDIR_ERROR(GetLastError());
1008
_PR_MD_MAKE_DIR(const char *name, PRIntn mode)
1011
SECURITY_ATTRIBUTES sa;
1012
LPSECURITY_ATTRIBUTES lpSA = NULL;
1013
PSECURITY_DESCRIPTOR pSD = NULL;
1016
if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable,
1017
&pSD, &pACL) == PR_SUCCESS) {
1018
sa.nLength = sizeof(sa);
1019
sa.lpSecurityDescriptor = pSD;
1020
sa.bInheritHandle = FALSE;
1023
rv = CreateDirectory(name, lpSA);
1025
_PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
1030
_PR_MD_MAP_MKDIR_ERROR(GetLastError());
1036
_PR_MD_RMDIR(const char *name)
1038
if (RemoveDirectory(name)) {
1041
_PR_MD_MAP_RMDIR_ERROR(GetLastError());
1047
_PR_MD_LOCKFILE(PRInt32 f)
1049
PRStatus rc = PR_SUCCESS;
1052
rv = LockFile( (HANDLE)f,
1054
0x0l, 0xffffffffl );
1056
DWORD rc = GetLastError();
1057
PR_LOG( _pr_io_lm, PR_LOG_ERROR,
1058
("_PR_MD_LOCKFILE() failed. Error: %d", rc ));
1063
} /* end _PR_MD_LOCKFILE() */
1066
_PR_MD_TLOCKFILE(PRInt32 f)
1068
PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
1070
} /* end _PR_MD_TLOCKFILE() */
1074
_PR_MD_UNLOCKFILE(PRInt32 f)
1078
rv = UnlockFile( (HANDLE) f,
1080
0x0l, 0xffffffffl );
1088
_PR_MD_MAP_DEFAULT_ERROR(GetLastError());
1091
} /* end _PR_MD_UNLOCKFILE() */
1094
_PR_MD_PIPEAVAILABLE(PRFileDesc *fd)
1097
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
1099
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1105
typedef HANDLE (WINAPI *CreateFileWFn) (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
1106
static CreateFileWFn createFileW = NULL;
1107
typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW);
1108
static FindFirstFileWFn findFirstFileW = NULL;
1109
typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW);
1110
static FindNextFileWFn findNextFileW = NULL;
1111
typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *);
1112
static GetFullPathNameWFn getFullPathNameW = NULL;
1113
typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR);
1114
static GetDriveTypeWFn getDriveTypeW = NULL;
1116
static void InitUnicodeSupport(void)
1121
* The W functions do not exist on Win9x. NSPR won't run on Win9x
1122
* if we call the W functions directly. Use GetProcAddress() to
1123
* look up their addresses at run time.
1126
module = GetModuleHandle("Kernel32.dll");
1131
createFileW = (CreateFileWFn)GetProcAddress(module, "CreateFileW");
1132
findFirstFileW = (FindFirstFileWFn)GetProcAddress(module, "FindFirstFileW");
1133
findNextFileW = (FindNextFileWFn)GetProcAddress(module, "FindNextFileW");
1134
getDriveTypeW = (GetDriveTypeWFn)GetProcAddress(module, "GetDriveTypeW");
1135
getFullPathNameW = (GetFullPathNameWFn)GetProcAddress(module, "GetFullPathNameW");
1138
/* ================ UTF16 Interfaces ================================ */
1139
void FlipSlashesW(PRUnichar *cp, int len)
1141
while (--len >= 0) {
1142
if (cp[0] == L'/') {
1147
} /* end FlipSlashesW() */
1150
_PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, int mode)
1156
SECURITY_ATTRIBUTES sa;
1157
LPSECURITY_ATTRIBUTES lpSA = NULL;
1158
PSECURITY_DESCRIPTOR pSD = NULL;
1162
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1166
if (osflags & PR_CREATE_FILE) {
1167
if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
1168
&pSD, &pACL) == PR_SUCCESS) {
1169
sa.nLength = sizeof(sa);
1170
sa.lpSecurityDescriptor = pSD;
1171
sa.bInheritHandle = FALSE;
1176
if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
1178
if (osflags & PR_RDONLY || osflags & PR_RDWR)
1179
access |= GENERIC_READ;
1180
if (osflags & PR_WRONLY || osflags & PR_RDWR)
1181
access |= GENERIC_WRITE;
1183
if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
1185
else if (osflags & PR_CREATE_FILE) {
1186
if (osflags & PR_TRUNCATE)
1187
flags = CREATE_ALWAYS;
1189
flags = OPEN_ALWAYS;
1191
if (osflags & PR_TRUNCATE)
1192
flags = TRUNCATE_EXISTING;
1194
flags = OPEN_EXISTING;
1197
file = createFileW(name,
1199
FILE_SHARE_READ|FILE_SHARE_WRITE,
1205
_PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
1207
if (file == INVALID_HANDLE_VALUE) {
1208
_PR_MD_MAP_OPEN_ERROR(GetLastError());
1212
return (PRInt32)file;
1216
_PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name)
1218
PRUnichar filename[ MAX_PATH ];
1221
if (!findFirstFileW) {
1222
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1227
/* Need 5 bytes for \*.* and the trailing null byte. */
1228
if (len + 5 > MAX_PATH) {
1229
PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
1232
wcscpy(filename, name);
1235
* If 'name' ends in a slash or backslash, do not append
1236
* another backslash.
1238
if (filename[len - 1] == L'/' || filename[len - 1] == L'\\') {
1241
wcscpy(&filename[len], L"\\*.*");
1242
FlipSlashesW( filename, wcslen(filename) );
1244
d->d_hdl = findFirstFileW( filename, &(d->d_entry) );
1245
if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
1246
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
1249
d->firstEntry = PR_TRUE;
1250
d->magic = _MD_MAGIC_DIR;
1255
_PR_MD_READ_DIR_UTF16(_MDDirUTF16 *d, PRIntn flags)
1259
PRUnichar *fileName;
1261
if (!findNextFileW) {
1262
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1268
if (d->firstEntry) {
1269
d->firstEntry = PR_FALSE;
1272
rv = findNextFileW(d->d_hdl, &(d->d_entry));
1277
fileName = GetFileFromDIR(d);
1278
if ( (flags & PR_SKIP_DOT) &&
1279
(fileName[0] == L'.') && (fileName[1] == L'\0'))
1281
if ( (flags & PR_SKIP_DOT_DOT) &&
1282
(fileName[0] == L'.') && (fileName[1] == L'.') &&
1283
(fileName[2] == L'\0'))
1285
if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
1289
err = GetLastError();
1290
PR_ASSERT(NO_ERROR != err);
1291
_PR_MD_MAP_READDIR_ERROR(err);
1294
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1299
_PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *d)
1302
if (FindClose(d->d_hdl)) {
1303
d->magic = (PRUint32)-1;
1306
_PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
1310
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1314
#define _PR_IS_W_SLASH(ch) ((ch) == L'/' || (ch) == L'\\')
1317
* IsRootDirectoryW --
1319
* Return PR_TRUE if the pathname 'fn' is a valid root directory,
1320
* else return PR_FALSE. The PRUnichar buffer pointed to by 'fn' must
1321
* be writable. During the execution of this function, the contents
1322
* of the buffer pointed to by 'fn' may be modified, but on return
1323
* the original contents will be restored. 'buflen' is the size of
1324
* the buffer pointed to by 'fn', in PRUnichars.
1326
* Root directories come in three formats:
1327
* 1. / or \, meaning the root directory of the current drive.
1328
* 2. C:/ or C:\, where C is a drive letter.
1329
* 3. \\<server name>\<share point name>\ or
1330
* \\<server name>\<share point name>, meaning the root directory
1331
* of a UNC (Universal Naming Convention) name.
1335
IsRootDirectoryW(PRUnichar *fn, size_t buflen)
1338
PRBool slashAdded = PR_FALSE;
1339
PRBool rv = PR_FALSE;
1341
if (_PR_IS_W_SLASH(fn[0]) && fn[1] == L'\0') {
1345
if (iswalpha(fn[0]) && fn[1] == L':' && _PR_IS_W_SLASH(fn[2])
1346
&& fn[3] == L'\0') {
1347
rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE;
1351
/* The UNC root directory */
1353
if (_PR_IS_W_SLASH(fn[0]) && _PR_IS_W_SLASH(fn[1])) {
1354
/* The 'server' part should have at least one character. */
1356
if (*p == L'\0' || _PR_IS_W_SLASH(*p)) {
1360
/* look for the next slash */
1363
} while (*p != L'\0' && !_PR_IS_W_SLASH(*p));
1368
/* The 'share' part should have at least one character. */
1370
if (*p == L'\0' || _PR_IS_W_SLASH(*p)) {
1374
/* look for the final slash */
1377
} while (*p != L'\0' && !_PR_IS_W_SLASH(*p));
1378
if (_PR_IS_W_SLASH(*p) && p[1] != L'\0') {
1383
* GetDriveType() doesn't work correctly if the
1384
* path is of the form \\server\share, so we add
1385
* a final slash temporarily.
1387
if ((p + 1) < (fn + buflen)) {
1390
slashAdded = PR_TRUE;
1392
return PR_FALSE; /* name too long */
1395
rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE;
1396
/* restore the 'fn' buffer */
1405
_PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info)
1408
WIN32_FIND_DATAW findFileData;
1409
PRUnichar pathbuf[MAX_PATH + 1];
1411
if (!findFirstFileW || !getFullPathNameW || !getDriveTypeW) {
1412
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1416
if (NULL == fn || L'\0' == *fn) {
1417
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1422
* FindFirstFile() expands wildcard characters. So
1423
* we make sure the pathname contains no wildcard.
1425
if (NULL != wcspbrk(fn, L"?*")) {
1426
PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0);
1430
hFindFile = findFirstFileW(fn, &findFileData);
1431
if (INVALID_HANDLE_VALUE == hFindFile) {
1433
PRUnichar *filePart;
1436
* FindFirstFile() does not work correctly on root directories.
1437
* It also doesn't work correctly on a pathname that ends in a
1438
* slash. So we first check to see if the pathname specifies a
1439
* root directory. If not, and if the pathname ends in a slash,
1440
* we remove the final slash and try again.
1444
* If the pathname does not contain ., \, and /, it cannot be
1445
* a root directory or a pathname that ends in a slash.
1447
if (NULL == wcspbrk(fn, L".\\/")) {
1448
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
1451
len = getFullPathNameW(fn, sizeof(pathbuf)/sizeof(pathbuf[0]), pathbuf,
1454
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
1457
if (len > sizeof(pathbuf)/sizeof(pathbuf[0])) {
1458
PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
1461
if (IsRootDirectoryW(pathbuf, sizeof(pathbuf)/sizeof(pathbuf[0]))) {
1462
info->type = PR_FILE_DIRECTORY;
1465
* These timestamps don't make sense for root directories.
1467
info->modifyTime = 0;
1468
info->creationTime = 0;
1471
if (!_PR_IS_W_SLASH(pathbuf[len - 1])) {
1472
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
1475
pathbuf[len - 1] = L'\0';
1476
hFindFile = findFirstFileW(pathbuf, &findFileData);
1477
if (INVALID_HANDLE_VALUE == hFindFile) {
1478
_PR_MD_MAP_OPENDIR_ERROR(GetLastError());
1484
FindClose(hFindFile);
1486
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1487
info->type = PR_FILE_DIRECTORY;
1489
info->type = PR_FILE_FILE;
1492
info->size = findFileData.nFileSizeHigh;
1493
info->size = (info->size << 32) + findFileData.nFileSizeLow;
1495
_PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);
1497
if (0 == findFileData.ftCreationTime.dwLowDateTime &&
1498
0 == findFileData.ftCreationTime.dwHighDateTime) {
1499
info->creationTime = info->modifyTime;
1501
_PR_FileTimeToPRTime(&findFileData.ftCreationTime,
1502
&info->creationTime);
1507
/* ================ end of UTF16 Interfaces ================================ */
1508
#endif /* MOZ_UNICODE */