[Vm-dev] [commit][3194] Integrate Marcel Taeumel' s well-written long-filename-support code for win32.

commits at squeakvm.org commits at squeakvm.org
Sat Dec 27 01:29:56 UTC 2014


Revision: 3194
Author:   eliot
Date:     2014-12-26 17:29:52 -0800 (Fri, 26 Dec 2014)
Log Message:
-----------
Integrate Marcel Taeumel's well-written long-filename-support code for win32.
Thanks Marcel!

Modified Paths:
--------------
    trunk/platforms/win32/plugins/FilePlugin/sqWin32FilePrims.c

Modified: trunk/platforms/win32/plugins/FilePlugin/sqWin32FilePrims.c
===================================================================
--- trunk/platforms/win32/plugins/FilePlugin/sqWin32FilePrims.c	2014-12-18 23:10:40 UTC (rev 3193)
+++ trunk/platforms/win32/plugins/FilePlugin/sqWin32FilePrims.c	2014-12-27 01:29:52 UTC (rev 3194)
@@ -15,8 +15,13 @@
 *     2) For using this you'll need to define WIN32_FILE_SUPPORT globally
 *        (e.g., in your compiler's project settings)
 *
+*   UPDATES:
+*     1) Support for long path names added by using UNC prefix in that case
+*        (Marcel Taeumel, Hasso Plattner Institute, Postdam, Germany)
+*
 *****************************************************************************/
 #include <windows.h>
+#include <malloc.h>
 #include "sq.h"
 #include "FilePlugin.h"
 
@@ -28,7 +33,7 @@
 #define false 0
 
 #define FILE_HANDLE(f) ((HANDLE) (f)->file)
-#define FAIL() return interpreterProxy->primitiveFail()
+#define FAIL() { return interpreterProxy->primitiveFail(); }
 
 /***
     The state of a file is kept in the following structure,
@@ -64,6 +69,46 @@
 /* answers if the file name in question has a case-sensitive duplicate */
 int hasCaseSensitiveDuplicate(WCHAR *path);
 
+/**
+    Converts multi-byte characters to wide characters. Handles paths longer
+    than 260 characters (including NULL) by prepending "\\?\" to encode UNC
+    paths as suggested in http://msdn.microsoft.com/en-us/library/windows/
+    desktop/aa365247%28v=vs.85%29.aspx#maxpath
+      "The maximum path of 32,767 characters is approximate,
+         because the "\\?\" prefix may be expanded to a longer
+         string by the system at run time, and this expansion
+         applies to the total length."
+    
+    Note that we do not check for the correct path component size,
+    which should be MAX_PATH in general but can vary between file systems.   
+    Actually, we should perform an additional check with
+    GetVolumneInformation to acquire lpMaximumComponentLength. 
+
+    Note that another possibility would be to use 8.3 aliases
+    for path components like the Windows Explorer does. However,
+    this feature also depends on the volume specifications.
+
+    Calling alloca() should be fine because we limit path length to 32k.
+    Stack size limit is much higher.
+**/
+#define ALLOC_WIN32_PATH(out_path, in_name, in_size) { \
+  int sz = MultiByteToWideChar(CP_UTF8, 0, in_name, in_size, NULL, 0); \
+  if(sz >= 32767) FAIL(); \
+  if(sz >= MAX_PATH) { \
+    out_path = (WCHAR*)alloca((sz + 4 + 1) * sizeof(WCHAR)); \
+    out_path[0] = L'\\'; out_path[1] = L'\\'; \
+    out_path[2] = L'?'; out_path[3] = L'\\'; \
+    MultiByteToWideChar(CP_UTF8, 0, in_name, in_size, out_path + 4, sz); \
+    out_path[sz + 4] = 0; \
+    sz += 4; \
+  } else { \
+    out_path = (WCHAR*)alloca((sz + 1) * sizeof(WCHAR)); \
+    MultiByteToWideChar(CP_UTF8, 0, in_name, in_size, out_path, sz); \
+    out_path[sz] = 0; \
+  } \
+}
+
+
 typedef union {
   struct {
     DWORD dwLow;
@@ -105,18 +150,16 @@
 }
 
 sqInt sqFileDeleteNameSize(char* fileNameIndex, sqInt fileNameSize) {
-  WCHAR win32Path[MAX_PATH+1];
-  int sz;
+  WCHAR *win32Path = NULL;
+
   /* convert the file name into a null-terminated C string */
-  sz = MultiByteToWideChar(CP_UTF8, 0, fileNameIndex, fileNameSize, NULL, 0);
-  if(sz > MAX_PATH)
-    FAIL();
-  MultiByteToWideChar(CP_UTF8, 0, fileNameIndex, fileNameSize, win32Path, sz);
-  win32Path[sz] = 0;
+  ALLOC_WIN32_PATH(win32Path, fileNameIndex, fileNameSize);
+
   if(hasCaseSensitiveDuplicate(win32Path))
     FAIL();
   if(!DeleteFileW(win32Path))
     FAIL();
+  
   return 1;
 }
 
@@ -157,15 +200,10 @@
      Squeak must take care of any line-end character mapping.
   */
   HANDLE h;
-  WCHAR win32Path[MAX_PATH+1];
-  int sz;
+  WCHAR *win32Path = NULL;
 
   /* convert the file name into a null-terminated C string */
-  sz = MultiByteToWideChar(CP_UTF8, 0, fileNameIndex, fileNameSize, NULL, 0);
-  if(sz > MAX_PATH)
-    FAIL();
-  MultiByteToWideChar(CP_UTF8, 0, fileNameIndex, fileNameSize, win32Path, sz);
-  win32Path[sz] = 0;
+  ALLOC_WIN32_PATH(win32Path, fileNameIndex, fileNameSize);
 
   if(hasCaseSensitiveDuplicate(win32Path)) {
     f->sessionID = 0;
@@ -254,28 +292,18 @@
 
 sqInt sqFileRenameOldSizeNewSize(char* oldNameIndex, sqInt oldNameSize, char* newNameIndex, sqInt newNameSize)
 {
-  WCHAR oldPath[MAX_PATH];
-  WCHAR newPath[MAX_PATH];
-  int sz;
+  WCHAR *oldPath = NULL;
+  WCHAR *newPath = NULL;
 
-  /* convert the file name into a null-terminated C string */
-  sz = MultiByteToWideChar(CP_UTF8, 0, oldNameIndex, oldNameSize, NULL,0);
-  if(sz > MAX_PATH)
-    FAIL();
-  MultiByteToWideChar(CP_UTF8, 0, oldNameIndex, oldNameSize, oldPath, sz);
-  oldPath[sz] = 0;
+  /* convert the file names into a null-terminated C string */
+  ALLOC_WIN32_PATH(oldPath, oldNameIndex, oldNameSize);
+  ALLOC_WIN32_PATH(newPath, newNameIndex, newNameSize);
 
-  /* convert the file name into a null-terminated C string */
-  sz = MultiByteToWideChar(CP_UTF8, 0, newNameIndex, newNameSize, NULL,0);
-  if(sz > MAX_PATH)
-    FAIL();
-  MultiByteToWideChar(CP_UTF8, 0, newNameIndex, newNameSize, newPath, sz);
-  newPath[sz] = 0;
-
   if(hasCaseSensitiveDuplicate(oldPath))
     FAIL();
   if(!MoveFileW(oldPath, newPath))
     FAIL();
+  
   return 1;
 }
 
@@ -359,8 +387,8 @@
 
 sqImageFile sqImageFileOpen(char *fileName, char *mode)
 { char *modePtr;
-  int sz, writeFlag = 0;
-  WCHAR win32Path[MAX_PATH];
+  int writeFlag = 0;
+  WCHAR *win32Path = NULL;
   HANDLE h;
 
   if(!mode) return 0;
@@ -373,13 +401,11 @@
       modePtr++;
     }
   /* convert the file name into a null-terminated C string */
-  sz = MultiByteToWideChar(CP_UTF8, 0, fileName, -1, NULL,0);
-  if(sz > MAX_PATH)
-    FAIL();
-  MultiByteToWideChar(CP_UTF8, 0, fileName, -1, win32Path, sz);
-  win32Path[sz] = 0;
+  ALLOC_WIN32_PATH(win32Path, fileName, -1);
 
-  if(hasCaseSensitiveDuplicate(win32Path)) return 0;
+  if(hasCaseSensitiveDuplicate(win32Path))
+    return 0;
+  
   h = CreateFileW(win32Path,
 		  writeFlag ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ,
 		  writeFlag ? FILE_SHARE_READ : (FILE_SHARE_READ | FILE_SHARE_WRITE),
@@ -387,7 +413,10 @@
 		  writeFlag ? CREATE_ALWAYS : OPEN_EXISTING,
 		  FILE_ATTRIBUTE_NORMAL,
 		  NULL /* No template */);
-  if(h == INVALID_HANDLE_VALUE) return 0;
+
+  if(h == INVALID_HANDLE_VALUE)
+    return 0;
+ 
   return (DWORD)h+1;
 }
 



More information about the Vm-dev mailing list