Looked up the W functions at runtime. NSPR_UNICODE_PATHNAME_BRANCH
authorwtc%netscape.com
Wed, 27 Nov 2002 02:40:33 +0000
branchNSPR_UNICODE_PATHNAME_BRANCH
changeset 2594 f44a8a81d9c2a4ca3a15ffa877eb98f137860d1d
parent 2593 5e30bd34280c3ff8a3baa4f73798eab54b65868b
push idunknown
push userunknown
push dateunknown
Looked up the W functions at runtime.
pr/include/md/_win95.h
pr/include/prio.h
pr/include/private/primpl.h
pr/src/io/prfile.c
pr/src/md/windows/w95io.c
pr/src/pthreads/ptio.c
--- a/pr/include/md/_win95.h
+++ b/pr/include/md/_win95.h
@@ -220,20 +220,21 @@ extern PRInt32 _MD_CloseFile(PRInt32 osf
 #define _MD_MAKE_DIR                  _PR_MD_MAKE_DIR
 #define _MD_RMDIR                     _PR_MD_RMDIR      
 #define _MD_LOCKFILE                  _PR_MD_LOCKFILE
 #define _MD_TLOCKFILE                 _PR_MD_TLOCKFILE
 #define _MD_UNLOCKFILE                _PR_MD_UNLOCKFILE
 
 #ifdef MOZ_UNICODE
 /* --- UTF16 IO stuff --- */
-#define _MD_OPEN_FILE_UTF16           _PR_MD_OPEN_FILE_UTF16 
-#define _MD_OPEN_DIR_UTF16            _PR_MD_OPEN_DIR_UTF16 
-#define _MD_READ_DIR_UTF16            _PR_MD_READ_DIR_UTF16 
+#define _MD_OPEN_FILE_UTF16           _PR_MD_OPEN_FILE_UTF16
+#define _MD_OPEN_DIR_UTF16            _PR_MD_OPEN_DIR_UTF16
+#define _MD_READ_DIR_UTF16            _PR_MD_READ_DIR_UTF16
 #define _MD_CLOSE_DIR_UTF16           _PR_MD_CLOSE_DIR_UTF16
+#define _MD_GETFILEINFO64_UTF16       _PR_MD_GETFILEINFO64_UTF16
 #endif /* MOZ_UNICODE */
 
 /* --- Socket IO stuff --- */
 #define _MD_EACCES                WSAEACCES
 #define _MD_EADDRINUSE            WSAEADDRINUSE
 #define _MD_EADDRNOTAVAIL         WSAEADDRNOTAVAIL
 #define _MD_EAFNOSUPPORT          WSAEAFNOSUPPORT
 #define _MD_EAGAIN                WSAEWOULDBLOCK
--- a/pr/include/prio.h
+++ b/pr/include/prio.h
@@ -837,16 +837,23 @@ struct PRFileInfo64 {
  *     PR_GetFileInfo returns PR_SUCCESS if file information is successfully
  *     obtained, otherwise it returns PR_FAILURE.
  ***************************************************************************
  */
 
 NSPR_API(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info);
 NSPR_API(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info);
 
+#ifdef MOZ_UNICODE
+/*
+ * EXPERIMENTAL: This function may be removed in a future release.
+ */
+NSPR_API(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info);
+#endif /* MOZ_UNICODE */
+
 /*
  **************************************************************************
  * FUNCTION: PR_GetOpenFileInfo, PR_GetOpenFileInfo64
  * DESCRIPTION:
  *     Get information about an open file referred to by the
  *     given PRFileDesc object.
  * INPUTS:
  *     const PRFileDesc *fd
--- a/pr/include/private/primpl.h
+++ b/pr/include/private/primpl.h
@@ -1155,16 +1155,19 @@ extern PRStatus _PR_MD_OPEN_DIR_UTF16(_M
 extern PRInt32 _PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, PRIntn mode);
 #define    _PR_MD_OPEN_FILE_UTF16 _MD_OPEN_FILE_UTF16
 
 extern PRUnichar * _PR_MD_READ_DIR_UTF16(_MDDirUTF16 *md, PRIntn flags);
 #define    _PR_MD_READ_DIR_UTF16 _MD_READ_DIR_UTF16
 
 extern PRInt32 _PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *md);
 #define    _PR_MD_CLOSE_DIR_UTF16 _MD_CLOSE_DIR_UTF16
+
+extern PRInt32 _PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info);
+#define _PR_MD_GETFILEINFO64_UTF16 _MD_GETFILEINFO64_UTF16
 #endif /* MOZ_UNICODE */
 
 /* Socket I/O related */
 extern void _PR_MD_INIT_IO(void);
 #define    _PR_MD_INIT_IO _MD_INIT_IO
 
 extern PRInt32 _PR_MD_CLOSE_SOCKET(PRInt32 osfd);
 #define    _PR_MD_CLOSE_SOCKET _MD_CLOSE_SOCKET
--- a/pr/src/io/prfile.c
+++ b/pr/src/io/prfile.c
@@ -804,10 +804,26 @@ PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF
             fd->secret->appendMode = appendMode;
 #endif
             _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
         }
     }
     return fd;
 }
  
+PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
+{
+#ifdef XP_MAC
+#pragma unused (fn, info)
+#endif
+    PRInt32 rv;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    rv = _PR_MD_GETFILEINFO64_UTF16(fn, info);
+    if (rv < 0) {
+        return PR_FAILURE;
+    } else {
+        return PR_SUCCESS;
+    }
+}
+
 /* ================ UTF16 Interfaces ================================ */
 #endif /* MOZ_UNICODE */
--- a/pr/src/md/windows/w95io.c
+++ b/pr/src/md/windows/w95io.c
@@ -37,17 +37,17 @@
  * Assumes synchronous I/O.
  *
  */
 
 #include "primpl.h"
 #include <direct.h>
 #include <mbstring.h>
 #ifdef MOZ_UNICODE
-#include <tchar.h>
+#include <wchar.h>
 #endif /* MOZ_UNICODE */
 
 
 struct _MDLock               _pr_ioq_lock;
 
 /*
  * NSPR-to-NT access right mapping table for files.
  */
@@ -72,16 +72,20 @@ static DWORD dirAccessTable[] = {
  * This constant is used by _PR_FileTimeToPRTime().
  */
 #if defined(__MINGW32__)
 static const PRTime _pr_filetime_offset = 116444736000000000LL;
 #else
 static const PRTime _pr_filetime_offset = 116444736000000000i64;
 #endif
 
+#ifdef MOZ_UNICODE
+static void InitUnicodeSupport(void);
+#endif
+
 void
 _PR_MD_INIT_IO()
 {
     WORD WSAVersion = 0x0101;
     WSADATA WSAData;
     int err;
 
     err = WSAStartup( WSAVersion, &WSAData );
@@ -108,16 +112,20 @@ void
 
         rv = SystemTimeToFileTime(&systime, &filetime.ft);
         PR_ASSERT(0 != rv);
         PR_ASSERT(filetime.prt == _pr_filetime_offset);
     }
 #endif /* DEBUG */
 
     _PR_NT_InitSids();
+
+#ifdef MOZ_UNICODE
+    InitUnicodeSupport();
+#endif
 }
 
 PRStatus
 _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
 {
     DWORD rv;
 
     PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
@@ -1088,16 +1096,50 @@ PRInt32
     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 = NULL; 
+typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW);
+static FindFirstFileWFn findFirstFileW = NULL; 
+typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW);
+static FindNextFileWFn findNextFileW = NULL; 
+typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *);
+static GetFullPathNameWFn getFullPathNameW = NULL; 
+typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR);
+static GetDriveTypeWFn getDriveTypeW = NULL; 
+
+static void InitUnicodeSupport(void)
+{
+    HMODULE module;
+
+    /*
+     * The W functions do not exist on Win9x.  NSPR won't run on Win9x
+     * if we call the W functions directly.  Use GetProcAddress() to
+     * look up their addresses at run time.
+     */
+
+    module = GetModuleHandle("Kernel32.dll");
+    if (!module) {
+        return;
+    }
+
+    createFileW = (CreateFileWFn)GetProcAddress(module, "CreateFileW"); 
+    findFirstFileW = (FindFirstFileWFn)GetProcAddress(module, "FindFirstFileW"); 
+    findNextFileW = (FindNextFileWFn)GetProcAddress(module, "FindNextFileW"); 
+    getDriveTypeW = (GetDriveTypeWFn)GetProcAddress(module, "GetDriveTypeW"); 
+    getFullPathNameW = (GetFullPathNameWFn)GetProcAddress(module, "GetFullPathNameW"); 
+}
+
 /* ================ UTF16 Interfaces ================================ */
 void FlipSlashesW(PRUnichar *cp, int len)
 {
     while (--len >= 0) {
         if (cp[0] == L'/') {
             cp[0] = L'\\';
         }
         cp++;
@@ -1110,16 +1152,21 @@ PRInt32
     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 (!createFileW) {
+        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+        return -1;
+    }
  
     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;
@@ -1142,17 +1189,17 @@ PRInt32
             flags = OPEN_ALWAYS;
     } else {
         if (osflags & PR_TRUNCATE)
             flags = TRUNCATE_EXISTING;
         else
             flags = OPEN_EXISTING;
     }
 
-    file = CreateFileW(name,
+    file = createFileW(name,
                        access,
                        FILE_SHARE_READ|FILE_SHARE_WRITE,
                        lpSA,
                        flags,
                        flag6,
                        NULL);
     if (lpSA != NULL) {
         _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
@@ -1166,16 +1213,21 @@ PRInt32
 }
  
 PRStatus
 _PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name)
 {
     PRUnichar filename[ MAX_PATH ];
     int len;
 
+    if (!findFirstFileW) {
+        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+        return PR_FAILURE;
+    }
+
     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);
 
@@ -1184,40 +1236,45 @@ PRStatus
      * 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) );
+    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 (!findNextFileW) {
+        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+        return NULL;
+    }
+
     if ( d ) {
         while (1) {
             if (d->firstEntry) {
                 d->firstEntry = PR_FALSE;
                 rv = 1;
             } else {
-                rv = FindNextFileW(d->d_hdl, &(d->d_entry));
+                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;
@@ -1249,10 +1306,203 @@ PRStatus
             _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
             return PR_FAILURE;
         }
     }
     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     return PR_FAILURE;
 }
 
+#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 (!findFirstFileW || !getFullPathNameW || !getDriveTypeW) {
+        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+        return -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 */
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -4807,12 +4807,18 @@ PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF1
     return NULL;
 }
 
 PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
 {
     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
     return NULL;
 }
+
+PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
 /* ================ UTF16 Interfaces ================================ */
 #endif /* MOZ_UNICODE */
 
 /* ptio.c */