| Index: mozilla/nsprpub/pr/src/md/windows/w95io.c
|
| ===================================================================
|
| --- mozilla/nsprpub/pr/src/md/windows/w95io.c (revision 191424)
|
| +++ mozilla/nsprpub/pr/src/md/windows/w95io.c (working copy)
|
| @@ -1,1753 +0,0 @@
|
| -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
| -/* This Source Code Form is subject to the terms of the Mozilla Public
|
| - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| -
|
| -/* Windows 95 IO module
|
| - *
|
| - * Assumes synchronous I/O.
|
| - *
|
| - */
|
| -
|
| -#include "primpl.h"
|
| -#include <direct.h>
|
| -#include <mbstring.h>
|
| -#ifdef MOZ_UNICODE
|
| -#include <wchar.h>
|
| -#endif /* MOZ_UNICODE */
|
| -
|
| -#ifdef WINCE
|
| -
|
| -static HANDLE CreateFileA(LPCSTR lpFileName,
|
| - DWORD dwDesiredAccess,
|
| - DWORD dwShareMode,
|
| - LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
| - DWORD dwCreationDisposition,
|
| - DWORD dwFlagsAndAttributes,
|
| - HANDLE hTemplateFile)
|
| -{
|
| - PRUnichar wFileName[MAX_PATH];
|
| - MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH);
|
| - return CreateFileW(wFileName, dwDesiredAccess, dwShareMode,
|
| - lpSecurityAttributes, dwCreationDisposition,
|
| - dwFlagsAndAttributes, hTemplateFile);
|
| -}
|
| -
|
| -/*
|
| - * We seem to call FindFirstFileA and FindNextFileA just to get
|
| - * the file names in a directory listing. If so, we could define
|
| - * a custom WIN32_FIND_DATAA structure with just the cFileName
|
| - * member, and the CopyFindFileDataW2A function could just
|
| - * copy/convert the cFileName member.
|
| - */
|
| -static void CopyFindFileDataW2A(LPWIN32_FIND_DATAW from,
|
| - LPWIN32_FIND_DATAA to)
|
| -{
|
| - /*
|
| - * WIN32_FIND_DATAA and WIN32_FIND_DATAW are slightly different.
|
| - * The dwReserved0, dwReserved1, and cAlternateFileName members
|
| - * exist only in WIN32_FIND_DATAA. The dwOID member exists only
|
| - * in WIN32_FIND_DATAW.
|
| - */
|
| - to->dwFileAttributes = from->dwFileAttributes;
|
| - to->ftCreationTime = from->ftCreationTime;
|
| - to->ftLastAccessTime = from->ftLastAccessTime;
|
| - to->ftLastWriteTime = from->ftLastWriteTime;
|
| - to->nFileSizeHigh = from->nFileSizeHigh;
|
| - to->nFileSizeLow = from->nFileSizeLow;
|
| - to->dwReserved0 = 0;
|
| - to->dwReserved1 = 0;
|
| - WideCharToMultiByte(CP_ACP, 0, from->cFileName, -1,
|
| - to->cFileName, MAX_PATH, NULL, NULL);
|
| - to->cAlternateFileName[0] = '\0';
|
| -}
|
| -
|
| -static HANDLE FindFirstFileA(LPCSTR lpFileName,
|
| - LPWIN32_FIND_DATAA lpFindFileData)
|
| -{
|
| - PRUnichar wFileName[MAX_PATH];
|
| - HANDLE hFindFile;
|
| - WIN32_FIND_DATAW wFindFileData;
|
| -
|
| - MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH);
|
| - hFindFile = FindFirstFileW(wFileName, &wFindFileData);
|
| - if (hFindFile != INVALID_HANDLE_VALUE) {
|
| - CopyFindFileDataW2A(&wFindFileData, lpFindFileData);
|
| - }
|
| - return hFindFile;
|
| -}
|
| -
|
| -static BOOL FindNextFileA(HANDLE hFindFile,
|
| - LPWIN32_FIND_DATAA lpFindFileData)
|
| -{
|
| - WIN32_FIND_DATAW wFindFileData;
|
| - BOOL rv;
|
| -
|
| - rv = FindNextFileW(hFindFile, &wFindFileData);
|
| - if (rv) {
|
| - CopyFindFileDataW2A(&wFindFileData, lpFindFileData);
|
| - }
|
| - return rv;
|
| -}
|
| -
|
| -static BOOL GetFileAttributesExA(LPCSTR lpFileName,
|
| - GET_FILEEX_INFO_LEVELS fInfoLevelId,
|
| - LPVOID lpFileInformation)
|
| -{
|
| - PRUnichar wFileName[MAX_PATH];
|
| - MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH);
|
| - return GetFileAttributesExW(wFileName, fInfoLevelId, lpFileInformation);
|
| -}
|
| -
|
| -static BOOL DeleteFileA(LPCSTR lpFileName)
|
| -{
|
| - PRUnichar wFileName[MAX_PATH];
|
| - MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, wFileName, MAX_PATH);
|
| - return DeleteFileW(wFileName);
|
| -}
|
| -
|
| -static BOOL MoveFileA(LPCSTR from, LPCSTR to)
|
| -{
|
| - PRUnichar wFrom[MAX_PATH];
|
| - PRUnichar wTo[MAX_PATH];
|
| - MultiByteToWideChar(CP_ACP, 0, from, -1, wFrom, MAX_PATH);
|
| - MultiByteToWideChar(CP_ACP, 0, to, -1, wTo, MAX_PATH);
|
| - return MoveFileW(wFrom, wTo);
|
| -}
|
| -
|
| -static BOOL CreateDirectoryA(LPCSTR lpPathName,
|
| - LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
| -{
|
| - PRUnichar wPathName[MAX_PATH];
|
| - MultiByteToWideChar(CP_ACP, 0, lpPathName, -1, wPathName, MAX_PATH);
|
| - return CreateDirectoryW(wPathName, lpSecurityAttributes);
|
| -}
|
| -
|
| -static BOOL RemoveDirectoryA(LPCSTR lpPathName)
|
| -{
|
| - PRUnichar wPathName[MAX_PATH];
|
| - MultiByteToWideChar(CP_ACP, 0, lpPathName, -1, wPathName, MAX_PATH);
|
| - return RemoveDirectoryW(wPathName);
|
| -}
|
| -
|
| -static long GetDriveType(const char *lpRootPathName)
|
| -{
|
| - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
| - return 0; // The drive type cannot be determined.
|
| -}
|
| -
|
| -static DWORD GetFullPathName(const char *lpFileName,
|
| - DWORD nBufferLength,
|
| - const char *lpBuffer,
|
| - const char **lpFilePart)
|
| -{
|
| - // needs work dft
|
| - DWORD len = strlen(lpFileName);
|
| - if (len > nBufferLength)
|
| - return len;
|
| -
|
| - strncpy((char *)lpBuffer, lpFileName, len);
|
| - ((char *)lpBuffer)[len] = '\0';
|
| -
|
| - if (lpFilePart) {
|
| - char *sep = strrchr(lpBuffer, '\\');
|
| - if (sep) {
|
| - sep++; // pass the seperator
|
| - *lpFilePart = sep;
|
| - } else {
|
| - *lpFilePart = lpBuffer;
|
| - }
|
| - }
|
| - return len;
|
| -}
|
| -
|
| -static BOOL LockFile(HANDLE hFile,
|
| - DWORD dwFileOffsetLow,
|
| - DWORD dwFileOffsetHigh,
|
| - DWORD nNumberOfBytesToLockLow,
|
| - DWORD nNumberOfBytesToLockHigh)
|
| -{
|
| - OVERLAPPED overlapped = {0};
|
| - overlapped.Offset = dwFileOffsetLow;
|
| - overlapped.OffsetHigh = dwFileOffsetHigh;
|
| - return LockFileEx(hFile,
|
| - LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
|
| - 0, // reserved
|
| - nNumberOfBytesToLockLow,
|
| - nNumberOfBytesToLockHigh, &overlapped);
|
| -}
|
| -
|
| -static BOOL UnlockFile(HANDLE hFile,
|
| - DWORD dwFileOffsetLow,
|
| - DWORD dwFileOffsetHigh,
|
| - DWORD nNumberOfBytesToUnlockLow,
|
| - DWORD nNumberOfBytesToUnlockHigh)
|
| -{
|
| - OVERLAPPED overlapped = {0};
|
| - overlapped.Offset = dwFileOffsetLow;
|
| - overlapped.OffsetHigh = dwFileOffsetHigh;
|
| - return UnlockFileEx(hFile,
|
| - 0, // reserved
|
| - nNumberOfBytesToUnlockLow,
|
| - nNumberOfBytesToUnlockHigh, &overlapped);
|
| -}
|
| -
|
| -static unsigned char *_mbsdec(const unsigned char *string1,
|
| - const unsigned char *string2)
|
| -{
|
| - // needs work dft
|
| - return NULL;
|
| -}
|
| -
|
| -static unsigned char *_mbsinc(const unsigned char *inCurrent)
|
| -{
|
| - // needs work dft
|
| - return (unsigned char *)(inCurrent + 1);
|
| -}
|
| -
|
| -#endif
|
| -
|
| -struct _MDLock _pr_ioq_lock;
|
| -
|
| -/*
|
| - * NSPR-to-NT access right mapping table for files.
|
| - */
|
| -static DWORD fileAccessTable[] = {
|
| - FILE_GENERIC_READ,
|
| - FILE_GENERIC_WRITE,
|
| - FILE_GENERIC_EXECUTE
|
| -};
|
| -
|
| -/*
|
| - * NSPR-to-NT access right mapping table for directories.
|
| - */
|
| -static DWORD dirAccessTable[] = {
|
| - FILE_GENERIC_READ,
|
| - FILE_GENERIC_WRITE|FILE_DELETE_CHILD,
|
| - FILE_GENERIC_EXECUTE
|
| -};
|
| -
|
| -/* Windows CE has GetFileAttributesEx. */
|
| -#ifndef WINCE
|
| -typedef BOOL (WINAPI *GetFileAttributesExFn)(LPCTSTR,
|
| - GET_FILEEX_INFO_LEVELS,
|
| - LPVOID);
|
| -static GetFileAttributesExFn getFileAttributesEx;
|
| -static void InitGetFileInfo(void);
|
| -#endif
|
| -
|
| -static void InitUnicodeSupport(void);
|
| -
|
| -static PRBool IsPrevCharSlash(const char *str, const char *current);
|
| -
|
| -void
|
| -_PR_MD_INIT_IO()
|
| -{
|
| - WORD WSAVersion = 0x0101;
|
| - WSADATA WSAData;
|
| - int err;
|
| -
|
| - err = WSAStartup( WSAVersion, &WSAData );
|
| - PR_ASSERT(0 == err);
|
| -
|
| -#ifdef DEBUG
|
| - /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */
|
| - {
|
| - SYSTEMTIME systime;
|
| - union {
|
| - PRTime prt;
|
| - FILETIME ft;
|
| - } filetime;
|
| - BOOL rv;
|
| -
|
| - systime.wYear = 1970;
|
| - systime.wMonth = 1;
|
| - /* wDayOfWeek is ignored */
|
| - systime.wDay = 1;
|
| - systime.wHour = 0;
|
| - systime.wMinute = 0;
|
| - systime.wSecond = 0;
|
| - systime.wMilliseconds = 0;
|
| -
|
| - rv = SystemTimeToFileTime(&systime, &filetime.ft);
|
| - PR_ASSERT(0 != rv);
|
| - PR_ASSERT(filetime.prt == _pr_filetime_offset);
|
| - }
|
| -#endif /* DEBUG */
|
| -
|
| - _PR_NT_InitSids();
|
| -
|
| -#ifndef WINCE
|
| - InitGetFileInfo();
|
| -#endif
|
| -
|
| - InitUnicodeSupport();
|
| -
|
| - _PR_MD_InitSockets();
|
| -}
|
| -
|
| -PRStatus
|
| -_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
|
| -{
|
| - DWORD rv;
|
| -
|
| - PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
|
| - INFINITE : PR_IntervalToMilliseconds(ticks);
|
| - rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
|
| - switch(rv)
|
| - {
|
| - case WAIT_OBJECT_0:
|
| - return PR_SUCCESS;
|
| - break;
|
| - case WAIT_TIMEOUT:
|
| - _PR_THREAD_LOCK(thread);
|
| - if (thread->state == _PR_IO_WAIT) {
|
| - ;
|
| - } else {
|
| - if (thread->wait.cvar != NULL) {
|
| - thread->wait.cvar = NULL;
|
| - _PR_THREAD_UNLOCK(thread);
|
| - } else {
|
| - /* The CVAR was notified just as the timeout
|
| - * occurred. This led to us being notified twice.
|
| - * call WaitForSingleObject() to clear the semaphore.
|
| - */
|
| - _PR_THREAD_UNLOCK(thread);
|
| - rv = WaitForSingleObject(thread->md.blocked_sema, 0);
|
| - PR_ASSERT(rv == WAIT_OBJECT_0);
|
| - }
|
| - }
|
| - return PR_SUCCESS;
|
| - break;
|
| - default:
|
| - return PR_FAILURE;
|
| - break;
|
| - }
|
| -}
|
| -PRStatus
|
| -_PR_MD_WAKEUP_WAITER(PRThread *thread)
|
| -{
|
| - if ( _PR_IS_NATIVE_THREAD(thread) )
|
| - {
|
| - if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE)
|
| - return PR_FAILURE;
|
| - else
|
| - return PR_SUCCESS;
|
| - }
|
| -}
|
| -
|
| -
|
| -/* --- FILE IO ----------------------------------------------------------- */
|
| -/*
|
| - * _PR_MD_OPEN() -- Open a file
|
| - *
|
| - * returns: a fileHandle
|
| - *
|
| - * The NSPR open flags (osflags) are translated into flags for Win95
|
| - *
|
| - * Mode seems to be passed in as a unix style file permissions argument
|
| - * as in 0666, in the case of opening the logFile.
|
| - *
|
| - */
|
| -PROsfd
|
| -_PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
|
| -{
|
| - HANDLE file;
|
| - PRInt32 access = 0;
|
| - PRInt32 flags = 0;
|
| - PRInt32 flag6 = 0;
|
| -
|
| - if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
|
| -
|
| - if (osflags & PR_RDONLY || osflags & PR_RDWR)
|
| - access |= GENERIC_READ;
|
| - if (osflags & PR_WRONLY || osflags & PR_RDWR)
|
| - access |= GENERIC_WRITE;
|
| -
|
| - if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
|
| - flags = CREATE_NEW;
|
| - else if (osflags & PR_CREATE_FILE) {
|
| - if (osflags & PR_TRUNCATE)
|
| - flags = CREATE_ALWAYS;
|
| - else
|
| - flags = OPEN_ALWAYS;
|
| - } else {
|
| - if (osflags & PR_TRUNCATE)
|
| - flags = TRUNCATE_EXISTING;
|
| - else
|
| - flags = OPEN_EXISTING;
|
| - }
|
| -
|
| - file = CreateFileA(name,
|
| - access,
|
| - FILE_SHARE_READ|FILE_SHARE_WRITE,
|
| - NULL,
|
| - flags,
|
| - flag6,
|
| - NULL);
|
| - if (file == INVALID_HANDLE_VALUE) {
|
| - _PR_MD_MAP_OPEN_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -
|
| - return (PROsfd)file;
|
| -}
|
| -
|
| -PROsfd
|
| -_PR_MD_OPEN_FILE(const char *name, PRIntn osflags, int mode)
|
| -{
|
| - HANDLE file;
|
| - PRInt32 access = 0;
|
| - PRInt32 flags = 0;
|
| - PRInt32 flag6 = 0;
|
| - SECURITY_ATTRIBUTES sa;
|
| - LPSECURITY_ATTRIBUTES lpSA = NULL;
|
| - PSECURITY_DESCRIPTOR pSD = NULL;
|
| - PACL pACL = NULL;
|
| -
|
| - if (osflags & PR_CREATE_FILE) {
|
| - if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
|
| - &pSD, &pACL) == PR_SUCCESS) {
|
| - sa.nLength = sizeof(sa);
|
| - sa.lpSecurityDescriptor = pSD;
|
| - sa.bInheritHandle = FALSE;
|
| - lpSA = &sa;
|
| - }
|
| - }
|
| -
|
| - if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
|
| -
|
| - if (osflags & PR_RDONLY || osflags & PR_RDWR)
|
| - access |= GENERIC_READ;
|
| - if (osflags & PR_WRONLY || osflags & PR_RDWR)
|
| - access |= GENERIC_WRITE;
|
| -
|
| - if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
|
| - flags = CREATE_NEW;
|
| - else if (osflags & PR_CREATE_FILE) {
|
| - if (osflags & PR_TRUNCATE)
|
| - flags = CREATE_ALWAYS;
|
| - else
|
| - flags = OPEN_ALWAYS;
|
| - } else {
|
| - if (osflags & PR_TRUNCATE)
|
| - flags = TRUNCATE_EXISTING;
|
| - else
|
| - flags = OPEN_EXISTING;
|
| - }
|
| -
|
| - file = CreateFileA(name,
|
| - access,
|
| - FILE_SHARE_READ|FILE_SHARE_WRITE,
|
| - lpSA,
|
| - flags,
|
| - flag6,
|
| - NULL);
|
| - if (lpSA != NULL) {
|
| - _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
|
| - }
|
| - if (file == INVALID_HANDLE_VALUE) {
|
| - _PR_MD_MAP_OPEN_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -
|
| - return (PROsfd)file;
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
|
| -{
|
| - PRUint32 bytes;
|
| - int rv, err;
|
| -
|
| - rv = ReadFile((HANDLE)fd->secret->md.osfd,
|
| - (LPVOID)buf,
|
| - len,
|
| - &bytes,
|
| - NULL);
|
| -
|
| - if (rv == 0)
|
| - {
|
| - err = GetLastError();
|
| - /* ERROR_HANDLE_EOF can only be returned by async io */
|
| - PR_ASSERT(err != ERROR_HANDLE_EOF);
|
| - if (err == ERROR_BROKEN_PIPE)
|
| - return 0;
|
| - else {
|
| - _PR_MD_MAP_READ_ERROR(err);
|
| - return -1;
|
| - }
|
| - }
|
| - return bytes;
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
|
| -{
|
| - PROsfd f = fd->secret->md.osfd;
|
| - PRInt32 bytes;
|
| - int rv;
|
| -
|
| - rv = WriteFile((HANDLE)f,
|
| - buf,
|
| - len,
|
| - &bytes,
|
| - NULL );
|
| -
|
| - if (rv == 0)
|
| - {
|
| - _PR_MD_MAP_WRITE_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| - return bytes;
|
| -} /* --- end _PR_MD_WRITE() --- */
|
| -
|
| -PROffset32
|
| -_PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
|
| -{
|
| - DWORD moveMethod;
|
| - PROffset32 rv;
|
| -
|
| - switch (whence) {
|
| - case PR_SEEK_SET:
|
| - moveMethod = FILE_BEGIN;
|
| - break;
|
| - case PR_SEEK_CUR:
|
| - moveMethod = FILE_CURRENT;
|
| - break;
|
| - case PR_SEEK_END:
|
| - moveMethod = FILE_END;
|
| - break;
|
| - default:
|
| - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
| - return -1;
|
| - }
|
| -
|
| - rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod);
|
| -
|
| - /*
|
| - * If the lpDistanceToMoveHigh argument (third argument) is
|
| - * NULL, SetFilePointer returns 0xffffffff on failure.
|
| - */
|
| - if (-1 == rv) {
|
| - _PR_MD_MAP_LSEEK_ERROR(GetLastError());
|
| - }
|
| - return rv;
|
| -}
|
| -
|
| -PROffset64
|
| -_PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence)
|
| -{
|
| - DWORD moveMethod;
|
| - LARGE_INTEGER li;
|
| - DWORD err;
|
| -
|
| - switch (whence) {
|
| - case PR_SEEK_SET:
|
| - moveMethod = FILE_BEGIN;
|
| - break;
|
| - case PR_SEEK_CUR:
|
| - moveMethod = FILE_CURRENT;
|
| - break;
|
| - case PR_SEEK_END:
|
| - moveMethod = FILE_END;
|
| - break;
|
| - default:
|
| - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
| - return -1;
|
| - }
|
| -
|
| - li.QuadPart = offset;
|
| - li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd,
|
| - li.LowPart, &li.HighPart, moveMethod);
|
| -
|
| - if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) {
|
| - _PR_MD_MAP_LSEEK_ERROR(err);
|
| - li.QuadPart = -1;
|
| - }
|
| - return li.QuadPart;
|
| -}
|
| -
|
| -/*
|
| - * This is documented to succeed on read-only files, but Win32's
|
| - * FlushFileBuffers functions fails with "access denied" in such a
|
| - * case. So we only signal an error if the error is *not* "access
|
| - * denied".
|
| - */
|
| -PRInt32
|
| -_PR_MD_FSYNC(PRFileDesc *fd)
|
| -{
|
| - /*
|
| - * From the documentation:
|
| - *
|
| - * On Windows NT, the function FlushFileBuffers fails if hFile
|
| - * is a handle to console output. That is because console
|
| - * output is not buffered. The function returns FALSE, and
|
| - * GetLastError returns ERROR_INVALID_HANDLE.
|
| - *
|
| - * On the other hand, on Win95, it returns without error. I cannot
|
| - * assume that 0, 1, and 2 are console, because if someone closes
|
| - * System.out and then opens a file, they might get file descriptor
|
| - * 1. An error on *that* version of 1 should be reported, whereas
|
| - * an error on System.out (which was the original 1) should be
|
| - * ignored. So I use isatty() to ensure that such an error was due
|
| - * to this bogosity, and if it was, I ignore the error.
|
| - */
|
| -
|
| - BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd);
|
| -
|
| - if (!ok) {
|
| - DWORD err = GetLastError();
|
| - if (err != ERROR_ACCESS_DENIED) { // from winerror.h
|
| - _PR_MD_MAP_FSYNC_ERROR(err);
|
| - return -1;
|
| - }
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -PRInt32
|
| -_MD_CloseFile(PROsfd osfd)
|
| -{
|
| - PRInt32 rv;
|
| -
|
| - rv = (CloseHandle((HANDLE)osfd))?0:-1;
|
| - if (rv == -1)
|
| - _PR_MD_MAP_CLOSE_ERROR(GetLastError());
|
| - return rv;
|
| -}
|
| -
|
| -
|
| -/* --- DIR IO ------------------------------------------------------------ */
|
| -#define GetFileFromDIR(d) (d)->d_entry.cFileName
|
| -#define FileIsHidden(d) ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
| -
|
| -static void FlipSlashes(char *cp, size_t len)
|
| -{
|
| - while (len-- > 0) {
|
| - if (cp[0] == '/') {
|
| - cp[0] = PR_DIRECTORY_SEPARATOR;
|
| - }
|
| - cp = _mbsinc(cp);
|
| - }
|
| -} /* end FlipSlashes() */
|
| -
|
| -
|
| -/*
|
| -**
|
| -** Local implementations of standard Unix RTL functions which are not provided
|
| -** by the VC RTL.
|
| -**
|
| -*/
|
| -
|
| -PRInt32
|
| -_PR_MD_CLOSE_DIR(_MDDir *d)
|
| -{
|
| - if ( d ) {
|
| - if (FindClose(d->d_hdl)) {
|
| - d->magic = (PRUint32)-1;
|
| - return 0;
|
| - } else {
|
| - _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| - }
|
| - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
| - return -1;
|
| -}
|
| -
|
| -
|
| -PRStatus
|
| -_PR_MD_OPEN_DIR(_MDDir *d, const char *name)
|
| -{
|
| - char filename[ MAX_PATH ];
|
| - size_t len;
|
| -
|
| - len = strlen(name);
|
| - /* Need 5 bytes for \*.* and the trailing null byte. */
|
| - if (len + 5 > MAX_PATH) {
|
| - PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
|
| - return PR_FAILURE;
|
| - }
|
| - strcpy(filename, name);
|
| -
|
| - /*
|
| - * If 'name' ends in a slash or backslash, do not append
|
| - * another backslash.
|
| - */
|
| - if (IsPrevCharSlash(filename, filename + len)) {
|
| - len--;
|
| - }
|
| - strcpy(&filename[len], "\\*.*");
|
| - FlipSlashes( filename, strlen(filename) );
|
| -
|
| - d->d_hdl = FindFirstFileA( filename, &(d->d_entry) );
|
| - if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
|
| - _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| - d->firstEntry = PR_TRUE;
|
| - d->magic = _MD_MAGIC_DIR;
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -char *
|
| -_PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
|
| -{
|
| - PRInt32 err;
|
| - BOOL rv;
|
| - char *fileName;
|
| -
|
| - if ( d ) {
|
| - while (1) {
|
| - if (d->firstEntry) {
|
| - d->firstEntry = PR_FALSE;
|
| - rv = 1;
|
| - } else {
|
| - rv = FindNextFileA(d->d_hdl, &(d->d_entry));
|
| - }
|
| - if (rv == 0) {
|
| - break;
|
| - }
|
| - fileName = GetFileFromDIR(d);
|
| - if ( (flags & PR_SKIP_DOT) &&
|
| - (fileName[0] == '.') && (fileName[1] == '\0'))
|
| - continue;
|
| - if ( (flags & PR_SKIP_DOT_DOT) &&
|
| - (fileName[0] == '.') && (fileName[1] == '.') &&
|
| - (fileName[2] == '\0'))
|
| - continue;
|
| - if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
|
| - continue;
|
| - return fileName;
|
| - }
|
| - err = GetLastError();
|
| - PR_ASSERT(NO_ERROR != err);
|
| - _PR_MD_MAP_READDIR_ERROR(err);
|
| - return NULL;
|
| - }
|
| - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
| - return NULL;
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_DELETE(const char *name)
|
| -{
|
| - if (DeleteFileA(name)) {
|
| - return 0;
|
| - } else {
|
| - _PR_MD_MAP_DELETE_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -}
|
| -
|
| -void
|
| -_PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm)
|
| -{
|
| - PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
|
| - CopyMemory(prtm, filetime, sizeof(PRTime));
|
| -#if defined(__MINGW32__)
|
| - *prtm = (*prtm - _pr_filetime_offset) / 10LL;
|
| -#else
|
| - *prtm = (*prtm - _pr_filetime_offset) / 10i64;
|
| -#endif
|
| -
|
| -#ifdef DEBUG
|
| - /* Doublecheck our calculation. */
|
| - {
|
| - SYSTEMTIME systime;
|
| - PRExplodedTime etm;
|
| - PRTime cmp; /* for comparison */
|
| - BOOL rv;
|
| -
|
| - rv = FileTimeToSystemTime(filetime, &systime);
|
| - PR_ASSERT(0 != rv);
|
| -
|
| - /*
|
| - * PR_ImplodeTime ignores wday and yday.
|
| - */
|
| - etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC;
|
| - etm.tm_sec = systime.wSecond;
|
| - etm.tm_min = systime.wMinute;
|
| - etm.tm_hour = systime.wHour;
|
| - etm.tm_mday = systime.wDay;
|
| - etm.tm_month = systime.wMonth - 1;
|
| - etm.tm_year = systime.wYear;
|
| - /*
|
| - * It is not well-documented what time zone the FILETIME's
|
| - * are in. WIN32_FIND_DATA is documented to be in UTC (GMT).
|
| - * But BY_HANDLE_FILE_INFORMATION is unclear about this.
|
| - * By our best judgement, we assume that FILETIME is in UTC.
|
| - */
|
| - etm.tm_params.tp_gmt_offset = 0;
|
| - etm.tm_params.tp_dst_offset = 0;
|
| - cmp = PR_ImplodeTime(&etm);
|
| -
|
| - /*
|
| - * SYSTEMTIME is in milliseconds precision, so we convert PRTime's
|
| - * microseconds to milliseconds before doing the comparison.
|
| - */
|
| - PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC));
|
| - }
|
| -#endif /* DEBUG */
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_STAT(const char *fn, struct stat *info)
|
| -{
|
| -#ifdef WINCE
|
| - // needs work. dft
|
| - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
| - return -1;
|
| -#else
|
| - PRInt32 rv;
|
| -
|
| - rv = _stat(fn, (struct _stat *)info);
|
| - if (-1 == rv) {
|
| - /*
|
| - * Check for MSVC runtime library _stat() bug.
|
| - * (It's really a bug in FindFirstFile().)
|
| - * If a pathname ends in a backslash or slash,
|
| - * e.g., c:\temp\ or c:/temp/, _stat() will fail.
|
| - * Note: a pathname ending in a slash (e.g., c:/temp/)
|
| - * can be handled by _stat() on NT but not on Win95.
|
| - *
|
| - * We remove the backslash or slash at the end and
|
| - * try again.
|
| - */
|
| -
|
| - size_t len = strlen(fn);
|
| - if (len > 0 && len <= _MAX_PATH
|
| - && IsPrevCharSlash(fn, fn + len)) {
|
| - char newfn[_MAX_PATH + 1];
|
| -
|
| - strcpy(newfn, fn);
|
| - newfn[len - 1] = '\0';
|
| - rv = _stat(newfn, (struct _stat *)info);
|
| - }
|
| - }
|
| -
|
| - if (-1 == rv) {
|
| - _PR_MD_MAP_STAT_ERROR(errno);
|
| - }
|
| - return rv;
|
| -#endif
|
| -}
|
| -
|
| -#define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\')
|
| -
|
| -static PRBool
|
| -IsPrevCharSlash(const char *str, const char *current)
|
| -{
|
| - const char *prev;
|
| -
|
| - if (str >= current)
|
| - return PR_FALSE;
|
| - prev = _mbsdec(str, current);
|
| - return (prev == current - 1) && _PR_IS_SLASH(*prev);
|
| -}
|
| -
|
| -/*
|
| - * IsRootDirectory --
|
| - *
|
| - * Return PR_TRUE if the pathname 'fn' is a valid root directory,
|
| - * else return PR_FALSE. The char buffer pointed to by 'fn' must
|
| - * be writable. During the execution of this function, the contents
|
| - * of the buffer pointed to by 'fn' may be modified, but on return
|
| - * the original contents will be restored. 'buflen' is the size of
|
| - * the buffer pointed to by 'fn'.
|
| - *
|
| - * Root directories come in three formats:
|
| - * 1. / or \, meaning the root directory of the current drive.
|
| - * 2. C:/ or C:\, where C is a drive letter.
|
| - * 3. \\<server name>\<share point name>\ or
|
| - * \\<server name>\<share point name>, meaning the root directory
|
| - * of a UNC (Universal Naming Convention) name.
|
| - */
|
| -
|
| -static PRBool
|
| -IsRootDirectory(char *fn, size_t buflen)
|
| -{
|
| - char *p;
|
| - PRBool slashAdded = PR_FALSE;
|
| - PRBool rv = PR_FALSE;
|
| -
|
| - if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') {
|
| - return PR_TRUE;
|
| - }
|
| -
|
| - if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2])
|
| - && fn[3] == '\0') {
|
| - rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
|
| - return rv;
|
| - }
|
| -
|
| - /* The UNC root directory */
|
| -
|
| - if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) {
|
| - /* The 'server' part should have at least one character. */
|
| - p = &fn[2];
|
| - if (*p == '\0' || _PR_IS_SLASH(*p)) {
|
| - return PR_FALSE;
|
| - }
|
| -
|
| - /* look for the next slash */
|
| - do {
|
| - p = _mbsinc(p);
|
| - } while (*p != '\0' && !_PR_IS_SLASH(*p));
|
| - if (*p == '\0') {
|
| - return PR_FALSE;
|
| - }
|
| -
|
| - /* The 'share' part should have at least one character. */
|
| - p++;
|
| - if (*p == '\0' || _PR_IS_SLASH(*p)) {
|
| - return PR_FALSE;
|
| - }
|
| -
|
| - /* look for the final slash */
|
| - do {
|
| - p = _mbsinc(p);
|
| - } while (*p != '\0' && !_PR_IS_SLASH(*p));
|
| - if (_PR_IS_SLASH(*p) && p[1] != '\0') {
|
| - return PR_FALSE;
|
| - }
|
| - if (*p == '\0') {
|
| - /*
|
| - * GetDriveType() doesn't work correctly if the
|
| - * path is of the form \\server\share, so we add
|
| - * a final slash temporarily.
|
| - */
|
| - if ((p + 1) < (fn + buflen)) {
|
| - *p++ = '\\';
|
| - *p = '\0';
|
| - slashAdded = PR_TRUE;
|
| - } else {
|
| - return PR_FALSE; /* name too long */
|
| - }
|
| - }
|
| - rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
|
| - /* restore the 'fn' buffer */
|
| - if (slashAdded) {
|
| - *--p = '\0';
|
| - }
|
| - }
|
| - return rv;
|
| -}
|
| -
|
| -#ifndef WINCE
|
| -/*
|
| - * InitGetFileInfo --
|
| - *
|
| - * Called during IO init. Checks for the existence of the system function
|
| - * GetFileAttributeEx, which when available is used in GETFILEINFO calls.
|
| - * If the routine exists, then the address of the routine is stored in the
|
| - * variable getFileAttributesEx, which will be used to call the routine.
|
| - */
|
| -static void InitGetFileInfo(void)
|
| -{
|
| - HMODULE module;
|
| - module = GetModuleHandle("Kernel32.dll");
|
| - if (!module) {
|
| - PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
|
| - ("InitGetFileInfo: GetModuleHandle() failed: %d",
|
| - GetLastError()));
|
| - return;
|
| - }
|
| -
|
| - getFileAttributesEx = (GetFileAttributesExFn)
|
| - GetProcAddress(module, "GetFileAttributesExA");
|
| -}
|
| -
|
| -/*
|
| - * If GetFileAttributeEx doesn't exist, we call FindFirstFile as a
|
| - * fallback.
|
| - */
|
| -static BOOL
|
| -GetFileAttributesExFB(const char *fn, WIN32_FIND_DATA *findFileData)
|
| -{
|
| - HANDLE hFindFile;
|
| -
|
| - /*
|
| - * FindFirstFile() expands wildcard characters. So
|
| - * we make sure the pathname contains no wildcard.
|
| - */
|
| - if (NULL != _mbspbrk(fn, "?*")) {
|
| - SetLastError(ERROR_INVALID_NAME);
|
| - return FALSE;
|
| - }
|
| -
|
| - hFindFile = FindFirstFile(fn, findFileData);
|
| - if (INVALID_HANDLE_VALUE == hFindFile) {
|
| - DWORD len;
|
| - char *filePart;
|
| - char pathbuf[MAX_PATH + 1];
|
| -
|
| - /*
|
| - * FindFirstFile() does not work correctly on root directories.
|
| - * It also doesn't work correctly on a pathname that ends in a
|
| - * slash. So we first check to see if the pathname specifies a
|
| - * root directory. If not, and if the pathname ends in a slash,
|
| - * we remove the final slash and try again.
|
| - */
|
| -
|
| - /*
|
| - * If the pathname does not contain ., \, and /, it cannot be
|
| - * a root directory or a pathname that ends in a slash.
|
| - */
|
| - if (NULL == _mbspbrk(fn, ".\\/")) {
|
| - return FALSE;
|
| - }
|
| - len = GetFullPathName(fn, sizeof(pathbuf), pathbuf,
|
| - &filePart);
|
| - if (0 == len) {
|
| - return FALSE;
|
| - }
|
| - if (len > sizeof(pathbuf)) {
|
| - SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
| - return FALSE;
|
| - }
|
| - if (IsRootDirectory(pathbuf, sizeof(pathbuf))) {
|
| - findFileData->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
| - /* The file size doesn't have a meaning for directories. */
|
| - findFileData->nFileSizeHigh = 0;
|
| - findFileData->nFileSizeLow = 0;
|
| - /*
|
| - * For a directory, these timestamps all specify when the
|
| - * directory is created. The creation time doesn't make
|
| - * sense for root directories, so we set it to (NSPR) time 0.
|
| - */
|
| - memcpy(&findFileData->ftCreationTime, &_pr_filetime_offset, 8);
|
| - findFileData->ftLastAccessTime = findFileData->ftCreationTime;
|
| - findFileData->ftLastWriteTime = findFileData->ftCreationTime;
|
| - return TRUE;
|
| - }
|
| - if (!IsPrevCharSlash(pathbuf, pathbuf + len)) {
|
| - return FALSE;
|
| - } else {
|
| - pathbuf[len - 1] = '\0';
|
| - hFindFile = FindFirstFile(pathbuf, findFileData);
|
| - if (INVALID_HANDLE_VALUE == hFindFile) {
|
| - return FALSE;
|
| - }
|
| - }
|
| - }
|
| -
|
| - FindClose(hFindFile);
|
| - return TRUE;
|
| -}
|
| -#endif
|
| -
|
| -PRInt32
|
| -_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
|
| -{
|
| -#ifdef WINCE
|
| - WIN32_FILE_ATTRIBUTE_DATA findFileData;
|
| -#else
|
| - WIN32_FIND_DATA findFileData;
|
| -#endif
|
| - BOOL rv;
|
| -
|
| - if (NULL == fn || '\0' == *fn) {
|
| - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
| - return -1;
|
| - }
|
| -
|
| -#ifdef WINCE
|
| - rv = GetFileAttributesExA(fn, GetFileExInfoStandard, &findFileData);
|
| -#else
|
| - /* GetFileAttributesEx is supported on Win 2K and up. */
|
| - if (getFileAttributesEx) {
|
| - rv = getFileAttributesEx(fn, GetFileExInfoStandard, &findFileData);
|
| - } else {
|
| - rv = GetFileAttributesExFB(fn, &findFileData);
|
| - }
|
| -#endif
|
| - if (!rv) {
|
| - _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -
|
| - if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
| - info->type = PR_FILE_DIRECTORY;
|
| - } else {
|
| - info->type = PR_FILE_FILE;
|
| - }
|
| -
|
| - info->size = findFileData.nFileSizeHigh;
|
| - info->size = (info->size << 32) + findFileData.nFileSizeLow;
|
| -
|
| - _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);
|
| -
|
| - if (0 == findFileData.ftCreationTime.dwLowDateTime &&
|
| - 0 == findFileData.ftCreationTime.dwHighDateTime) {
|
| - info->creationTime = info->modifyTime;
|
| - } else {
|
| - _PR_FileTimeToPRTime(&findFileData.ftCreationTime,
|
| - &info->creationTime);
|
| - }
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
|
| -{
|
| - PRFileInfo64 info64;
|
| - PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64);
|
| - if (0 == rv)
|
| - {
|
| - info->type = info64.type;
|
| - info->size = (PRUint32) info64.size;
|
| - info->modifyTime = info64.modifyTime;
|
| - info->creationTime = info64.creationTime;
|
| - }
|
| - return rv;
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
|
| -{
|
| - int rv;
|
| -
|
| - BY_HANDLE_FILE_INFORMATION hinfo;
|
| -
|
| - rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo);
|
| - if (rv == FALSE) {
|
| - _PR_MD_MAP_FSTAT_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -
|
| - if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
| - info->type = PR_FILE_DIRECTORY;
|
| - else
|
| - info->type = PR_FILE_FILE;
|
| -
|
| - info->size = hinfo.nFileSizeHigh;
|
| - info->size = (info->size << 32) + hinfo.nFileSizeLow;
|
| -
|
| - _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) );
|
| - _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) );
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
|
| -{
|
| - PRFileInfo64 info64;
|
| - int rv = _PR_MD_GETOPENFILEINFO64(fd, &info64);
|
| - if (0 == rv)
|
| - {
|
| - info->type = info64.type;
|
| - info->modifyTime = info64.modifyTime;
|
| - info->creationTime = info64.creationTime;
|
| - LL_L2I(info->size, info64.size);
|
| - }
|
| - return rv;
|
| -}
|
| -
|
| -PRStatus
|
| -_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable)
|
| -{
|
| -#ifdef WINCE
|
| - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
| - return PR_FAILURE;
|
| -#else
|
| - BOOL rv;
|
| -
|
| - /*
|
| - * The SetHandleInformation function fails with the
|
| - * ERROR_CALL_NOT_IMPLEMENTED error on Win95.
|
| - */
|
| - rv = SetHandleInformation(
|
| - (HANDLE)fd->secret->md.osfd,
|
| - HANDLE_FLAG_INHERIT,
|
| - inheritable ? HANDLE_FLAG_INHERIT : 0);
|
| - if (0 == rv) {
|
| - _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| - return PR_SUCCESS;
|
| -#endif
|
| -}
|
| -
|
| -void
|
| -_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported)
|
| -{
|
| - if (imported) {
|
| - fd->secret->inheritable = _PR_TRI_UNKNOWN;
|
| - } else {
|
| - fd->secret->inheritable = _PR_TRI_FALSE;
|
| - }
|
| -}
|
| -
|
| -void
|
| -_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd)
|
| -{
|
| -#ifdef WINCE
|
| - fd->secret->inheritable = _PR_TRI_FALSE;
|
| -#else
|
| - DWORD flags;
|
| -
|
| - PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
|
| - if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) {
|
| - if (flags & HANDLE_FLAG_INHERIT) {
|
| - fd->secret->inheritable = _PR_TRI_TRUE;
|
| - } else {
|
| - fd->secret->inheritable = _PR_TRI_FALSE;
|
| - }
|
| - }
|
| -#endif
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_RENAME(const char *from, const char *to)
|
| -{
|
| - /* Does this work with dot-relative pathnames? */
|
| - if (MoveFileA(from, to)) {
|
| - return 0;
|
| - } else {
|
| - _PR_MD_MAP_RENAME_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_ACCESS(const char *name, PRAccessHow how)
|
| -{
|
| -#ifdef WINCE
|
| - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
| - return -1;
|
| -#else
|
| -PRInt32 rv;
|
| - switch (how) {
|
| - case PR_ACCESS_WRITE_OK:
|
| - rv = _access(name, 02);
|
| - break;
|
| - case PR_ACCESS_READ_OK:
|
| - rv = _access(name, 04);
|
| - break;
|
| - case PR_ACCESS_EXISTS:
|
| - return _access(name, 00);
|
| - break;
|
| - default:
|
| - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
| - return -1;
|
| - }
|
| - if (rv < 0)
|
| - _PR_MD_MAP_ACCESS_ERROR(errno);
|
| - return rv;
|
| -#endif
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_MKDIR(const char *name, PRIntn mode)
|
| -{
|
| - /* XXXMB - how to translate the "mode"??? */
|
| - if (CreateDirectoryA(name, NULL)) {
|
| - return 0;
|
| - } else {
|
| - _PR_MD_MAP_MKDIR_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_MAKE_DIR(const char *name, PRIntn mode)
|
| -{
|
| - BOOL rv;
|
| - SECURITY_ATTRIBUTES sa;
|
| - LPSECURITY_ATTRIBUTES lpSA = NULL;
|
| - PSECURITY_DESCRIPTOR pSD = NULL;
|
| - PACL pACL = NULL;
|
| -
|
| - if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable,
|
| - &pSD, &pACL) == PR_SUCCESS) {
|
| - sa.nLength = sizeof(sa);
|
| - sa.lpSecurityDescriptor = pSD;
|
| - sa.bInheritHandle = FALSE;
|
| - lpSA = &sa;
|
| - }
|
| - rv = CreateDirectoryA(name, lpSA);
|
| - if (lpSA != NULL) {
|
| - _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
|
| - }
|
| - if (rv) {
|
| - return 0;
|
| - } else {
|
| - _PR_MD_MAP_MKDIR_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_RMDIR(const char *name)
|
| -{
|
| - if (RemoveDirectoryA(name)) {
|
| - return 0;
|
| - } else {
|
| - _PR_MD_MAP_RMDIR_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -}
|
| -
|
| -PRStatus
|
| -_PR_MD_LOCKFILE(PROsfd f)
|
| -{
|
| - PRStatus rc = PR_SUCCESS;
|
| - DWORD rv;
|
| -
|
| - rv = LockFile( (HANDLE)f,
|
| - 0l, 0l,
|
| - 0x0l, 0xffffffffl );
|
| - if ( rv == 0 ) {
|
| - DWORD rc = GetLastError();
|
| - PR_LOG( _pr_io_lm, PR_LOG_ERROR,
|
| - ("_PR_MD_LOCKFILE() failed. Error: %d", rc ));
|
| - rc = PR_FAILURE;
|
| - }
|
| -
|
| - return rc;
|
| -} /* end _PR_MD_LOCKFILE() */
|
| -
|
| -PRStatus
|
| -_PR_MD_TLOCKFILE(PROsfd f)
|
| -{
|
| - PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
|
| - return PR_FAILURE;
|
| -} /* end _PR_MD_TLOCKFILE() */
|
| -
|
| -
|
| -PRStatus
|
| -_PR_MD_UNLOCKFILE(PROsfd f)
|
| -{
|
| - PRInt32 rv;
|
| -
|
| - rv = UnlockFile( (HANDLE) f,
|
| - 0l, 0l,
|
| - 0x0l, 0xffffffffl );
|
| -
|
| - if ( rv )
|
| - {
|
| - return PR_SUCCESS;
|
| - }
|
| - else
|
| - {
|
| - _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| -} /* end _PR_MD_UNLOCKFILE() */
|
| -
|
| -PRInt32
|
| -_PR_MD_PIPEAVAILABLE(PRFileDesc *fd)
|
| -{
|
| - if (NULL == fd)
|
| - PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
|
| - else
|
| - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
| - return -1;
|
| -}
|
| -
|
| -#ifdef MOZ_UNICODE
|
| -
|
| -typedef HANDLE (WINAPI *CreateFileWFn) (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
|
| -static CreateFileWFn createFileW = CreateFileW;
|
| -typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW);
|
| -static FindFirstFileWFn findFirstFileW = FindFirstFileW;
|
| -typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW);
|
| -static FindNextFileWFn findNextFileW = FindNextFileW;
|
| -typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *);
|
| -static GetFullPathNameWFn getFullPathNameW = GetFullPathNameW;
|
| -typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR);
|
| -static GetDriveTypeWFn getDriveTypeW = GetDriveTypeW;
|
| -
|
| -#endif /* MOZ_UNICODE */
|
| -
|
| -PRBool _pr_useUnicode = PR_FALSE;
|
| -
|
| -static void InitUnicodeSupport(void)
|
| -{
|
| -#ifdef WINCE
|
| - /* The A functions don't even exist in Windows Mobile. */
|
| - _pr_useUnicode = PR_TRUE;
|
| -#else
|
| - /*
|
| - * The W functions exist on Win9x as stubs that fail with the
|
| - * ERROR_CALL_NOT_IMPLEMENTED error. We plan to emulate the
|
| - * MSLU W functions on Win9x in the future.
|
| - */
|
| -
|
| - /* Find out if we are running on a Unicode enabled version of Windows */
|
| - OSVERSIONINFOA osvi = {0};
|
| -
|
| - osvi.dwOSVersionInfoSize = sizeof(osvi);
|
| - if (GetVersionExA(&osvi)) {
|
| - _pr_useUnicode = (osvi.dwPlatformId >= VER_PLATFORM_WIN32_NT);
|
| - } else {
|
| - _pr_useUnicode = PR_FALSE;
|
| - }
|
| -#ifdef DEBUG
|
| - /*
|
| - * In debug builds, allow explicit use of ANSI methods to simulate
|
| - * a Win9x environment for testing purposes.
|
| - */
|
| - if (getenv("WINAPI_USE_ANSI"))
|
| - _pr_useUnicode = PR_FALSE;
|
| -#endif
|
| -#endif
|
| -}
|
| -
|
| -#ifdef MOZ_UNICODE
|
| -
|
| -/* ================ UTF16 Interfaces ================================ */
|
| -static void FlipSlashesW(PRUnichar *cp, size_t len)
|
| -{
|
| - while (len-- > 0) {
|
| - if (cp[0] == L'/') {
|
| - cp[0] = L'\\';
|
| - }
|
| - cp++;
|
| - }
|
| -} /* end FlipSlashesW() */
|
| -
|
| -PROsfd
|
| -_PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, int mode)
|
| -{
|
| - HANDLE file;
|
| - PRInt32 access = 0;
|
| - PRInt32 flags = 0;
|
| - PRInt32 flag6 = 0;
|
| - SECURITY_ATTRIBUTES sa;
|
| - LPSECURITY_ATTRIBUTES lpSA = NULL;
|
| - PSECURITY_DESCRIPTOR pSD = NULL;
|
| - PACL pACL = NULL;
|
| -
|
| - if (osflags & PR_CREATE_FILE) {
|
| - if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
|
| - &pSD, &pACL) == PR_SUCCESS) {
|
| - sa.nLength = sizeof(sa);
|
| - sa.lpSecurityDescriptor = pSD;
|
| - sa.bInheritHandle = FALSE;
|
| - lpSA = &sa;
|
| - }
|
| - }
|
| -
|
| - if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
|
| -
|
| - if (osflags & PR_RDONLY || osflags & PR_RDWR)
|
| - access |= GENERIC_READ;
|
| - if (osflags & PR_WRONLY || osflags & PR_RDWR)
|
| - access |= GENERIC_WRITE;
|
| -
|
| - if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
|
| - flags = CREATE_NEW;
|
| - else if (osflags & PR_CREATE_FILE) {
|
| - if (osflags & PR_TRUNCATE)
|
| - flags = CREATE_ALWAYS;
|
| - else
|
| - flags = OPEN_ALWAYS;
|
| - } else {
|
| - if (osflags & PR_TRUNCATE)
|
| - flags = TRUNCATE_EXISTING;
|
| - else
|
| - flags = OPEN_EXISTING;
|
| - }
|
| -
|
| - file = createFileW(name,
|
| - access,
|
| - FILE_SHARE_READ|FILE_SHARE_WRITE,
|
| - lpSA,
|
| - flags,
|
| - flag6,
|
| - NULL);
|
| - if (lpSA != NULL) {
|
| - _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
|
| - }
|
| - if (file == INVALID_HANDLE_VALUE) {
|
| - _PR_MD_MAP_OPEN_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| -
|
| - return (PROsfd)file;
|
| -}
|
| -
|
| -PRStatus
|
| -_PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name)
|
| -{
|
| - PRUnichar filename[ MAX_PATH ];
|
| - int len;
|
| -
|
| - len = wcslen(name);
|
| - /* Need 5 bytes for \*.* and the trailing null byte. */
|
| - if (len + 5 > MAX_PATH) {
|
| - PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
|
| - return PR_FAILURE;
|
| - }
|
| - wcscpy(filename, name);
|
| -
|
| - /*
|
| - * If 'name' ends in a slash or backslash, do not append
|
| - * another backslash.
|
| - */
|
| - if (filename[len - 1] == L'/' || filename[len - 1] == L'\\') {
|
| - len--;
|
| - }
|
| - wcscpy(&filename[len], L"\\*.*");
|
| - FlipSlashesW( filename, wcslen(filename) );
|
| -
|
| - d->d_hdl = findFirstFileW( filename, &(d->d_entry) );
|
| - if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
|
| - _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| - d->firstEntry = PR_TRUE;
|
| - d->magic = _MD_MAGIC_DIR;
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -PRUnichar *
|
| -_PR_MD_READ_DIR_UTF16(_MDDirUTF16 *d, PRIntn flags)
|
| -{
|
| - PRInt32 err;
|
| - BOOL rv;
|
| - PRUnichar *fileName;
|
| -
|
| - if ( d ) {
|
| - while (1) {
|
| - if (d->firstEntry) {
|
| - d->firstEntry = PR_FALSE;
|
| - rv = 1;
|
| - } else {
|
| - rv = findNextFileW(d->d_hdl, &(d->d_entry));
|
| - }
|
| - if (rv == 0) {
|
| - break;
|
| - }
|
| - fileName = GetFileFromDIR(d);
|
| - if ( (flags & PR_SKIP_DOT) &&
|
| - (fileName[0] == L'.') && (fileName[1] == L'\0'))
|
| - continue;
|
| - if ( (flags & PR_SKIP_DOT_DOT) &&
|
| - (fileName[0] == L'.') && (fileName[1] == L'.') &&
|
| - (fileName[2] == L'\0'))
|
| - continue;
|
| - if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
|
| - continue;
|
| - return fileName;
|
| - }
|
| - err = GetLastError();
|
| - PR_ASSERT(NO_ERROR != err);
|
| - _PR_MD_MAP_READDIR_ERROR(err);
|
| - return NULL;
|
| - }
|
| - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
| - return NULL;
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *d)
|
| -{
|
| - if ( d ) {
|
| - if (FindClose(d->d_hdl)) {
|
| - d->magic = (PRUint32)-1;
|
| - return 0;
|
| - } else {
|
| - _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| - }
|
| - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
| - return -1;
|
| -}
|
| -
|
| -#define _PR_IS_W_SLASH(ch) ((ch) == L'/' || (ch) == L'\\')
|
| -
|
| -/*
|
| - * IsRootDirectoryW --
|
| - *
|
| - * Return PR_TRUE if the pathname 'fn' is a valid root directory,
|
| - * else return PR_FALSE. The PRUnichar buffer pointed to by 'fn' must
|
| - * be writable. During the execution of this function, the contents
|
| - * of the buffer pointed to by 'fn' may be modified, but on return
|
| - * the original contents will be restored. 'buflen' is the size of
|
| - * the buffer pointed to by 'fn', in PRUnichars.
|
| - *
|
| - * Root directories come in three formats:
|
| - * 1. / or \, meaning the root directory of the current drive.
|
| - * 2. C:/ or C:\, where C is a drive letter.
|
| - * 3. \\<server name>\<share point name>\ or
|
| - * \\<server name>\<share point name>, meaning the root directory
|
| - * of a UNC (Universal Naming Convention) name.
|
| - */
|
| -
|
| -static PRBool
|
| -IsRootDirectoryW(PRUnichar *fn, size_t buflen)
|
| -{
|
| - PRUnichar *p;
|
| - PRBool slashAdded = PR_FALSE;
|
| - PRBool rv = PR_FALSE;
|
| -
|
| - if (_PR_IS_W_SLASH(fn[0]) && fn[1] == L'\0') {
|
| - return PR_TRUE;
|
| - }
|
| -
|
| - if (iswalpha(fn[0]) && fn[1] == L':' && _PR_IS_W_SLASH(fn[2])
|
| - && fn[3] == L'\0') {
|
| - rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE;
|
| - return rv;
|
| - }
|
| -
|
| - /* The UNC root directory */
|
| -
|
| - if (_PR_IS_W_SLASH(fn[0]) && _PR_IS_W_SLASH(fn[1])) {
|
| - /* The 'server' part should have at least one character. */
|
| - p = &fn[2];
|
| - if (*p == L'\0' || _PR_IS_W_SLASH(*p)) {
|
| - return PR_FALSE;
|
| - }
|
| -
|
| - /* look for the next slash */
|
| - do {
|
| - p++;
|
| - } while (*p != L'\0' && !_PR_IS_W_SLASH(*p));
|
| - if (*p == L'\0') {
|
| - return PR_FALSE;
|
| - }
|
| -
|
| - /* The 'share' part should have at least one character. */
|
| - p++;
|
| - if (*p == L'\0' || _PR_IS_W_SLASH(*p)) {
|
| - return PR_FALSE;
|
| - }
|
| -
|
| - /* look for the final slash */
|
| - do {
|
| - p++;
|
| - } while (*p != L'\0' && !_PR_IS_W_SLASH(*p));
|
| - if (_PR_IS_W_SLASH(*p) && p[1] != L'\0') {
|
| - return PR_FALSE;
|
| - }
|
| - if (*p == L'\0') {
|
| - /*
|
| - * GetDriveType() doesn't work correctly if the
|
| - * path is of the form \\server\share, so we add
|
| - * a final slash temporarily.
|
| - */
|
| - if ((p + 1) < (fn + buflen)) {
|
| - *p++ = L'\\';
|
| - *p = L'\0';
|
| - slashAdded = PR_TRUE;
|
| - } else {
|
| - return PR_FALSE; /* name too long */
|
| - }
|
| - }
|
| - rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE;
|
| - /* restore the 'fn' buffer */
|
| - if (slashAdded) {
|
| - *--p = L'\0';
|
| - }
|
| - }
|
| - return rv;
|
| -}
|
| -
|
| -PRInt32
|
| -_PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info)
|
| -{
|
| - HANDLE hFindFile;
|
| - WIN32_FIND_DATAW findFileData;
|
| - PRUnichar pathbuf[MAX_PATH + 1];
|
| -
|
| - if (NULL == fn || L'\0' == *fn) {
|
| - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
| - return -1;
|
| - }
|
| -
|
| - /*
|
| - * FindFirstFile() expands wildcard characters. So
|
| - * we make sure the pathname contains no wildcard.
|
| - */
|
| - if (NULL != wcspbrk(fn, L"?*")) {
|
| - PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0);
|
| - return -1;
|
| - }
|
| -
|
| - hFindFile = findFirstFileW(fn, &findFileData);
|
| - if (INVALID_HANDLE_VALUE == hFindFile) {
|
| - DWORD len;
|
| - PRUnichar *filePart;
|
| -
|
| - /*
|
| - * FindFirstFile() does not work correctly on root directories.
|
| - * It also doesn't work correctly on a pathname that ends in a
|
| - * slash. So we first check to see if the pathname specifies a
|
| - * root directory. If not, and if the pathname ends in a slash,
|
| - * we remove the final slash and try again.
|
| - */
|
| -
|
| - /*
|
| - * If the pathname does not contain ., \, and /, it cannot be
|
| - * a root directory or a pathname that ends in a slash.
|
| - */
|
| - if (NULL == wcspbrk(fn, L".\\/")) {
|
| - _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| - len = getFullPathNameW(fn, sizeof(pathbuf)/sizeof(pathbuf[0]), pathbuf,
|
| - &filePart);
|
| - if (0 == len) {
|
| - _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| - if (len > sizeof(pathbuf)/sizeof(pathbuf[0])) {
|
| - PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
|
| - return -1;
|
| - }
|
| - if (IsRootDirectoryW(pathbuf, sizeof(pathbuf)/sizeof(pathbuf[0]))) {
|
| - info->type = PR_FILE_DIRECTORY;
|
| - info->size = 0;
|
| - /*
|
| - * These timestamps don't make sense for root directories.
|
| - */
|
| - info->modifyTime = 0;
|
| - info->creationTime = 0;
|
| - return 0;
|
| - }
|
| - if (!_PR_IS_W_SLASH(pathbuf[len - 1])) {
|
| - _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
|
| - return -1;
|
| - } else {
|
| - pathbuf[len - 1] = L'\0';
|
| - hFindFile = findFirstFileW(pathbuf, &findFileData);
|
| - if (INVALID_HANDLE_VALUE == hFindFile) {
|
| - _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
|
| - return -1;
|
| - }
|
| - }
|
| - }
|
| -
|
| - FindClose(hFindFile);
|
| -
|
| - if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
| - info->type = PR_FILE_DIRECTORY;
|
| - } else {
|
| - info->type = PR_FILE_FILE;
|
| - }
|
| -
|
| - info->size = findFileData.nFileSizeHigh;
|
| - info->size = (info->size << 32) + findFileData.nFileSizeLow;
|
| -
|
| - _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);
|
| -
|
| - if (0 == findFileData.ftCreationTime.dwLowDateTime &&
|
| - 0 == findFileData.ftCreationTime.dwHighDateTime) {
|
| - info->creationTime = info->modifyTime;
|
| - } else {
|
| - _PR_FileTimeToPRTime(&findFileData.ftCreationTime,
|
| - &info->creationTime);
|
| - }
|
| -
|
| - return 0;
|
| -}
|
| -/* ================ end of UTF16 Interfaces ================================ */
|
| -#endif /* MOZ_UNICODE */
|
|
|