[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