Speed up #linkInfoOf: (especially on networked files)
authorStefan Vogel <sv@exept.de>
Wed, 22 Jul 2009 22:43:09 +0200
changeset 11804 2596279cafb6
parent 11803 1f0585980edf
child 11805 28b3ead51d73
Speed up #linkInfoOf: (especially on networked files) by using the GetFileAttributesExW() windows call.
Win32OperatingSystem.st
--- a/Win32OperatingSystem.st	Wed Jul 22 12:01:59 2009 +0200
+++ b/Win32OperatingSystem.st	Wed Jul 22 22:43:09 2009 +0200
@@ -35,7 +35,7 @@
 
 Object subclass:#FileStatusInfo
 	instanceVariableNames:'type mode uid gid size id accessed modified created statusChanged
-		fullName alternativeName sourcePath linkTargetPath'
+		sourcePath linkTargetPath fullPathName alternativePathName'
 	classVariableNames:''
 	poolDictionaries:''
 	privateIn:Win32OperatingSystem
@@ -4928,12 +4928,114 @@
     "Modified: / 05-07-2006 / 16:56:06 / cg"
 !
 
+getLongPathName:aPathName
+    "get the full (long, not 8.3) version of aPathName"
+
+%{
+    int ret;
+    wchar_t _aPathName[MAX_PATH+1];
+
+    if (__isString(aPathName)) {
+        int i;
+        int l = __stringSize(aPathName);
+        if (l > MAX_PATH) l = MAX_PATH;
+
+        for (i=0; i<l; i++) {
+            _aPathName[i] = __stringVal(aPathName)[i];
+        }
+        _aPathName[i] = 0;
+    } else if (__isUnicode16String(aPathName)) {
+        int i;
+        int l = __unicode16StringSize(aPathName);
+        if (l > MAX_PATH) l = MAX_PATH;
+
+        for (i=0; i<l; i++) {
+            _aPathName[i] = __unicode16StringVal(aPathName)[i];
+        }
+        _aPathName[i] = 0;
+    } else
+        goto badArgument;
+
+#ifdef DO_WRAP_CALLS
+     do {
+         __threadErrno = 0;
+         ret = STX_API_CALL3( "GetLongPathNameW", GetLongPathNameW, _aPathName, _aPathName, MAX_PATH+1);
+     } while ((ret == 0) && (__threadErrno == EINTR));
+#else
+     ret = GetLongPathNameW(_aPathName, _aPathName, MAX_PATH+1);
+     if (ret == 0) {
+         __threadErrno = __WIN32_ERR(GetLastError());
+     }
+#endif
+     RETURN ( __MKU16STRING(_aPathName));
+
+badArgument:;
+%}.
+    ^ self primitiveFailed
+
+    "
+     self getLongPathName:'x:\'
+     self getLongPathName:'c:\Dokumente und Einstellungen'
+    "
+!
+
 getNullDevice
     "get the name of the null-device."
 
     ^ 'nul:'
 !
 
+getShortPathName:aPathName
+    "get the full (long, not 8.3) version of aPathName"
+
+%{
+    int ret;
+    wchar_t _aPathName[MAX_PATH+1];
+
+    if (__isString(aPathName)) {
+        int i;
+        int l = __stringSize(aPathName);
+        if (l > MAX_PATH) l = MAX_PATH;
+
+        for (i=0; i<l; i++) {
+            _aPathName[i] = __stringVal(aPathName)[i];
+        }
+        _aPathName[i] = 0;
+    } else if (__isUnicode16String(aPathName)) {
+        int i;
+        int l = __unicode16StringSize(aPathName);
+        if (l > MAX_PATH) l = MAX_PATH;
+
+        for (i=0; i<l; i++) {
+            _aPathName[i] = __unicode16StringVal(aPathName)[i];
+        }
+        _aPathName[i] = 0;
+    } else
+        goto badArgument;
+
+#ifdef DO_WRAP_CALLS
+     do {
+         __threadErrno = 0;
+         ret = STX_API_CALL3( "GetShortPathNameW", GetShortPathNameW, _aPathName, _aPathName, MAX_PATH+1);
+     } while ((ret == 0) && (__threadErrno == EINTR));
+#else
+     ret = GetShortPathNameW(_aPathName, _aPathName, MAX_PATH+1);
+     if (ret == 0) {
+         __threadErrno = __WIN32_ERR(GetLastError());
+     }
+#endif
+     RETURN ( __MKU16STRING(_aPathName));
+
+badArgument:;
+%}.
+    ^ self primitiveFailed
+
+    "
+     self getShortPathName:'x:\'
+     self getShortPathName:'c:\Dokumente und Einstellungen'
+    "
+!
+
 getVolumeInformation: rootPath
     name: volumeNameBuffer
     nameSize: volumeNameSize
@@ -5381,7 +5483,7 @@
      fileName alternativeName|
 
 %{
-    HANDLE hFile = (HANDLE)0;
+    BOOL result;
     int ret;
     wchar_t alternativeFileNameBuffer[15];
     wchar_t fileNameBuffer[MAX_PATH+1];
@@ -5390,7 +5492,7 @@
     SYSTEMTIME accessTime;
     SYSTEMTIME modificationTime;
     int modeBits = 0;
-    WIN32_FIND_DATAW findStructW;
+    WIN32_FILE_ATTRIBUTE_DATA fileAttributeData;
     unsigned INT ino;
     wchar_t _aPathName[MAX_PATH+1];
 
@@ -5419,46 +5521,44 @@
     {
         do {
             __threadErrno = 0;
-            hFile = STX_API_CALL2( "FindFirstFileW", FindFirstFileW, _aPathName, &findStructW);
-        } while ((hFile < 0) && (__threadErrno == EINTR));
-    }
-#else
-    hFile = FindFirstFileW(_aPathName, &findStructW);
-    if (hFile < 0) {
+            result = STX_API_CALL3( "GetFileAttributesExW", GetFileAttributesExW, _aPathName, GetFileExInfoStandard, &fileAttributeData);
+        } while (!result && (__threadErrno == EINTR));
+    }
+#else
+    result = FindFirstFileW(_aPathName, GetFileExInfoStandard, &fileAttributeData);
+    if (!result) {
         __threadErrno = __WIN32_ERR(GetLastError());
     }
 #endif
 
-    if (! hFile || (hFile == (HANDLE)(-1)) || (hFile == INVALID_HANDLE_VALUE)) {
+    if (!result) {
         @global(LastErrorNumber) = __mkSmallInteger(__threadErrno);
     } else {
-        FindClose(hFile);
-
         id = __mkSmallInteger(0);   /* could get it by opening ... */
-        size = __MKLARGEINT64(1, findStructW.nFileSizeLow, findStructW.nFileSizeHigh);
-
-        if (findStructW.cFileName[0] != '\0') {
-            bcopy(findStructW.cFileName, fileNameBuffer, MAX_PATH*sizeof(wchar_t));
-            fileNameBuffer[MAX_PATH] = '\0';
-            fileName = __MKU16STRING(fileNameBuffer);             /* FULL name */
-        }
-
-        if (findStructW.cAlternateFileName[0] != '\0') {
-            bcopy(findStructW.cAlternateFileName, alternativeFileNameBuffer, 14*sizeof(wchar_t));
-            alternativeFileNameBuffer[14] = '\0';
-            alternativeName = __MKU16STRING(alternativeFileNameBuffer); /* DOS name */
-        }
+        size = __MKLARGEINT64(1, fileAttributeData.nFileSizeLow, fileAttributeData.nFileSizeHigh);
+
+//        if (fileAttributeData.cFileName[0] != '\0') {
+//            bcopy(fileAttributeData.cFileName, fileNameBuffer, MAX_PATH*sizeof(wchar_t));
+//            fileNameBuffer[MAX_PATH] = '\0';
+//            fileName = __MKU16STRING(fileNameBuffer);             /* FULL name */
+//        }
+
+//        if (fileAttributeData.cAlternateFileName[0] != '\0') {
+//            bcopy(fileAttributeData.cAlternateFileName, alternativeFileNameBuffer, 14*sizeof(wchar_t));
+//            alternativeFileNameBuffer[14] = '\0';
+//            alternativeName = __MKU16STRING(alternativeFileNameBuffer); /* DOS name */
+//        }
 
         /*
          * simulate access bits
          */
-        if (findStructW.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+        if (fileAttributeData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
             modeBits = 0444;
         } else {
             modeBits = 0666;
         }
 
-        if (findStructW.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+        if (fileAttributeData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
             type = @symbol(directory);
             modeBits = 0777;   /* executable and WRITABLE - why? please refer to #isWritable: */
         } else {
@@ -5470,13 +5570,13 @@
         /*
          * sigh - convert from stupid time to useful time
          */
-        FileTimeToLocalFileTime(&findStructW.ftCreationTime, &tempFileTime);
+        FileTimeToLocalFileTime(&fileAttributeData.ftCreationTime, &tempFileTime);
         FileTimeToSystemTime(&tempFileTime, &creationTime);
 
-        FileTimeToLocalFileTime(&findStructW.ftLastAccessTime, &tempFileTime);
+        FileTimeToLocalFileTime(&fileAttributeData.ftLastAccessTime, &tempFileTime);
         FileTimeToSystemTime(&tempFileTime, &accessTime);
 
-        FileTimeToLocalFileTime(&findStructW.ftLastWriteTime, &tempFileTime);
+        FileTimeToLocalFileTime(&fileAttributeData.ftLastWriteTime, &tempFileTime);
         FileTimeToSystemTime(&tempFileTime, &modificationTime);
 
         aYr  = __mkSmallInteger(accessTime.wYear);
@@ -11013,7 +11113,40 @@
     "return the files other name (DOS name on windows).
      Nil if there is no other name"
 
-    ^ alternativeName
+    |path idx|
+
+    path := self alternativePathName.
+    path notNil ifTrue:[
+        idx := path lastIndexOf:$\ startingAt:path size-1.
+        idx ~~ 0 ifTrue:[
+            path := path copyFrom:(idx+1).
+        ].
+    ].
+
+    ^ path
+
+    "
+        'C:\' asFilename info alternativeName
+        'C:\Dokumente und Einstellungen\' asFilename info alternativeName
+        'C:\Dokumente und Einstellungen' asFilename info alternativeName
+    "
+!
+
+alternativePathName
+    "return the files real name (non-DOS name on windows).
+     Nil if there is no other name"
+
+    "/ access lazily...
+    alternativePathName isNil ifTrue:[
+        alternativePathName := OperatingSystem getShortPathName:sourcePath.
+    ].
+
+    ^ alternativePathName
+
+    "
+        'C:\' asFilename info alternativePathName
+        'C:\Dokumente und Einstellungen' asFilename info alternativePathName
+    "
 !
 
 creationTime
@@ -11032,7 +11165,40 @@
     "return the files real name (non-DOS name on windows).
      Nil if there is no other name"
 
-    ^ fullName
+    |path idx|
+
+    path := self fullPathName.
+    path notNil ifTrue:[
+        idx := path lastIndexOf:$\ startingAt:path size-1.
+        idx ~~ 0 ifTrue:[
+            path := path copyFrom:(idx+1).
+        ].
+    ].
+
+    ^ path
+
+    "
+        '\' asFilename info fullName
+        'C:\' asFilename info fullName
+        'C:\Dokumente und Einstellungen' asFilename info fullName
+    "
+!
+
+fullPathName
+    "return the files real name (non-DOS name on windows).
+     Nil if there is no other name"
+
+    "/ access lazily...
+    fullPathName isNil ifTrue:[
+        fullPathName := OperatingSystem getLongPathName:sourcePath.
+    ].
+
+    ^ fullPathName
+
+    "
+        'C:\' asFilename info fullPathName
+        'C:\Dokumente und Einstellungen' asFilename info fullPathName
+    "
 !
 
 gid
@@ -11195,8 +11361,8 @@
     modified := mT.
     created := cT.
     sourcePath := lP.
-    fullName := name1.
-    alternativeName := name2.
+    fullPathName := name1.
+    alternativePathName := name2.
 ! !
 
 !Win32OperatingSystem::FileStatusInfo methodsFor:'queries-access'!
@@ -16063,7 +16229,7 @@
 !Win32OperatingSystem class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.370 2009-07-20 17:05:21 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.371 2009-07-22 20:43:09 stefan Exp $'
 ! !
 
 Win32OperatingSystem initialize!