ntdll / kernel32: #39

Eric Pouech pouech-eric at wanadoo.fr
Sat Dec 13 04:01:17 CST 2003


this patch:
- reimplements Get{Full|Short|Long}PathName using only ntdll or kernel32 
APIs
- fixes a couple of bugs in previous implementation
- removed the (now useless) todo_wine:s in the regression tests
- added invalid character testing in RtlIsNameLegalDOS8Dot3
- moved these APIs to kernel32/path.c (new file)

A+
-- 
Eric Pouech
-------------- next part --------------
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel38/Makefile.in dlls/kernel/Makefile.in
--- dlls/kernel38/Makefile.in	2003-12-06 16:09:08.000000000 +0100
+++ dlls/kernel/Makefile.in	2003-12-12 21:33:31.000000000 +0100
@@ -51,6 +51,7 @@
 	module.c \
 	ne_module.c \
 	ne_segment.c \
+	path.c \
 	powermgnt.c \
 	process.c \
 	profile.c \
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel38/path.c dlls/kernel/path.c
--- dlls/kernel38/path.c	1970-01-01 01:00:00.000000000 +0100
+++ dlls/kernel/path.c	2003-12-13 10:30:11.000000000 +0100
@@ -0,0 +1,440 @@
+/*
+ * File handling functions
+ *
+ * Copyright 1993 Erik Bos
+ * Copyright 1996 Alexandre Julliard
+ * Copyright 2003 Eric Pouech
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "winerror.h"
+#include "ntstatus.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winternl.h"
+#include "wincon.h"
+#include "wine/winbase16.h"
+#include "kernel_private.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+#include "async.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(file);
+
+#define MAX_PATHNAME_LEN        1024
+
+
+/***********************************************************************
+ *           GetFullPathNameW   (KERNEL32.@)
+ * NOTES
+ *   if the path closed with '\', *lastpart is 0
+ */
+DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer,
+                               LPWSTR *lastpart )
+{
+    LPWSTR      dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(buffer));
+    DWORD       ret;
+
+    if (!dst) return 0;
+    ret = RtlGetFullPathName_U(name, len * sizeof(WCHAR), dst, lastpart) / sizeof(WCHAR);
+    if (ret < len)
+    {
+        strcpyW(buffer, dst);
+        if (lastpart && *lastpart) *lastpart = buffer + (*lastpart - dst);
+    }
+    HeapFree(GetProcessHeap(), 0, dst);
+    return ret;
+}
+
+/***********************************************************************
+ *           GetFullPathNameA   (KERNEL32.@)
+ * NOTES
+ *   if the path closed with '\', *lastpart is 0
+ */
+DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer,
+                               LPSTR *lastpart )
+{
+    UNICODE_STRING nameW;
+    WCHAR bufferW[MAX_PATH];
+    DWORD ret, retW;
+
+    if (!name)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+
+    if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name))
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return 0;
+    }
+
+    retW = GetFullPathNameW( nameW.Buffer, MAX_PATH, bufferW, NULL);
+
+    if (!retW)
+        ret = 0;
+    else if (retW > MAX_PATH)
+    {
+        SetLastError(ERROR_FILENAME_EXCED_RANGE);
+        ret = 0;
+    }
+    else
+    {
+        ret = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
+        if (ret && ret <= len)
+        {
+            WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, len, NULL, NULL);
+            ret--; /* length without 0 */
+
+            if (lastpart)
+            {
+                LPSTR p = buffer + strlen(buffer) - 1;
+
+                if (*p != '\\')
+                {
+                    while ((p > buffer + 2) && (*p != '\\')) p--;
+                    *lastpart = p + 1;
+                }
+                else *lastpart = NULL;
+            }
+        }
+    }
+
+    RtlFreeUnicodeString(&nameW);
+    return ret;
+}
+
+
+/***********************************************************************
+ *           GetLongPathNameW   (KERNEL32.@)
+ *
+ * NOTES
+ *  observed (Win2000):
+ *  shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
+ *  shortpath="":   LastError=ERROR_PATH_NOT_FOUND, ret=0
+ */
+DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen )
+{
+    WCHAR               tmplongpath[MAX_PATHNAME_LEN];
+    LPCWSTR             p;
+    DWORD               sp = 0, lp = 0;
+    DWORD               tmplen;
+    BOOL                unixabsolute = (shortpath[0] == '/');
+    WIN32_FIND_DATAW    wfd;
+    HANDLE              goit;
+
+    if (!shortpath)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    if (!shortpath[0]) 
+    {
+        SetLastError(ERROR_PATH_NOT_FOUND);
+        return 0;
+    }
+
+    TRACE("%s,%p,%ld\n", debugstr_w(shortpath), longpath, longlen);
+
+    if (shortpath[0] == '\\' && shortpath[1] == '\\')
+    {
+        ERR("UNC pathname %s\n", debugstr_w(shortpath));
+        lstrcpynW( longpath, shortpath, longlen );
+        return strlenW(longpath);
+    }
+
+    /* check for drive letter */
+    if (!unixabsolute && shortpath[1] == ':' )
+    {
+        tmplongpath[0] = shortpath[0];
+        tmplongpath[1] = ':';
+        lp = sp = 2;
+    }
+
+    while (shortpath[sp]) 
+    {
+        /* check for path delimiters and reproduce them */
+        if (shortpath[sp] == '\\' || shortpath[sp] == '/') 
+        {
+            if (!lp || tmplongpath[lp-1] != '\\')
+            {
+                /* strip double "\\" */
+                tmplongpath[lp++] = '\\';
+            }
+            tmplongpath[lp] = 0; /* terminate string */
+            sp++;
+            continue;
+        }
+
+        p = shortpath + sp;
+        if (sp == 0 && p[0] == '.' && (p[1] == '/' || p[1] == '\\'))
+        {
+            tmplongpath[lp++] = *p++;
+            tmplongpath[lp++] = *p++;
+        }
+        for (; *p && *p != '/' && *p != '\\'; p++);
+        tmplen = p - (shortpath + sp);
+        lstrcpynW(tmplongpath + lp, shortpath + sp, tmplen + 1);
+        /* Check if the file exists and use the existing file name */
+        goit = FindFirstFileW(tmplongpath, &wfd);
+        if (goit == INVALID_HANDLE_VALUE)
+        {       
+            TRACE("not found %s!\n", debugstr_w(tmplongpath));
+            SetLastError ( ERROR_FILE_NOT_FOUND );
+            return 0;
+        }
+        FindClose(goit);
+        strcpyW(tmplongpath + lp, wfd.cFileName);
+        lp += strlenW(tmplongpath + lp);
+        sp += tmplen;
+    }
+    tmplen = strlenW(shortpath) - 1;
+    if ((shortpath[tmplen] == '/' || shortpath[tmplen] == '\\') &&
+        (tmplongpath[lp - 1] != '/' && tmplongpath[lp - 1] != '\\'))
+        tmplongpath[lp++] = shortpath[tmplen];
+    tmplongpath[lp] = 0;
+
+    tmplen = strlenW(tmplongpath) + 1;
+    if (tmplen <= longlen)
+    {
+        strcpyW(longpath, tmplongpath);
+        TRACE("returning %s\n", debugstr_w(longpath));
+        tmplen--; /* length without 0 */
+    }
+
+    return tmplen;
+}
+
+/***********************************************************************
+ *           GetLongPathNameA   (KERNEL32.@)
+ */
+DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen )
+{
+    UNICODE_STRING shortpathW;
+    WCHAR longpathW[MAX_PATH];
+    DWORD ret, retW;
+
+    if (!shortpath)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+
+    TRACE("%s\n", debugstr_a(shortpath));
+
+    if (!RtlCreateUnicodeStringFromAsciiz(&shortpathW, shortpath))
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return 0;
+    }
+
+    retW = GetLongPathNameW(shortpathW.Buffer, longpathW, MAX_PATH);
+
+    if (!retW)
+        ret = 0;
+    else if (retW > MAX_PATH)
+    {
+        SetLastError(ERROR_FILENAME_EXCED_RANGE);
+        ret = 0;
+    }
+    else
+    {
+        ret = WideCharToMultiByte(CP_ACP, 0, longpathW, -1, NULL, 0, NULL, NULL);
+        if (ret <= longlen)
+        {
+            WideCharToMultiByte(CP_ACP, 0, longpathW, -1, longpath, longlen, NULL, NULL);
+            ret--; /* length without 0 */
+        }
+    }
+
+    RtlFreeUnicodeString(&shortpathW);
+    return ret;
+}
+
+
+/***********************************************************************
+ *           GetShortPathNameW   (KERNEL32.@)
+ *
+ * NOTES
+ *  observed:
+ *  longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
+ *  longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0
+ *
+ * more observations ( with NT 3.51 (WinDD) ):
+ * longpath <= 8.3 -> just copy longpath to shortpath
+ * longpath > 8.3  ->
+ *             a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND
+ *             b) file does exist     -> set the short filename.
+ * - trailing slashes are reproduced in the short name, even if the
+ *   file is not a directory
+ * - the absolute/relative path of the short name is reproduced like found
+ *   in the long name
+ * - longpath and shortpath may have the same address
+ * Peter Ganten, 1999
+ */
+DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortlen )
+{
+    WCHAR               tmpshortpath[MAX_PATHNAME_LEN];
+    LPCWSTR             p;
+    DWORD               sp = 0, lp = 0;
+    DWORD               tmplen;
+    BOOL                unixabsolute = (longpath[0] == '/');
+    WIN32_FIND_DATAW    wfd;
+    HANDLE              goit;
+    UNICODE_STRING      ustr;
+    WCHAR               ustr_buf[8+1+3+1];
+
+    TRACE("%s\n", debugstr_w(longpath));
+
+    if (!longpath)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+    if (!longpath[0])
+    {
+        SetLastError(ERROR_BAD_PATHNAME);
+        return 0;
+    }
+
+    /* check for drive letter */
+    if (!unixabsolute && longpath[1] == ':' )
+    {
+        tmpshortpath[0] = longpath[0];
+        tmpshortpath[1] = ':';
+        sp = lp = 2;
+    }
+
+    ustr.Buffer = ustr_buf;
+    ustr.Length = 0;
+    ustr.MaximumLength = sizeof(ustr_buf);
+
+    while (longpath[lp]) 
+    {
+        /* check for path delimiters and reproduce them */
+        if (longpath[lp] == '\\' || longpath[lp] == '/') 
+        {
+            if (!sp || tmpshortpath[sp-1] != '\\')
+            {
+                /* strip double "\\" */
+                tmpshortpath[sp] = '\\';
+                sp++;
+            }
+            tmpshortpath[sp] = 0; /* terminate string */
+            lp++;
+            continue;
+        }
+
+        for (p = longpath + lp; *p && *p != '/' && *p != '\\'; p++);
+        tmplen = p - (longpath + lp);
+        lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1);
+        if (tmplen <= 8+1+3+1)
+        {
+            memcpy(ustr_buf, longpath + lp, tmplen * sizeof(WCHAR));
+            ustr_buf[tmplen] = '\0';
+            ustr.Length = tmplen * sizeof(WCHAR);
+            /* Check, if the current element is a valid dos name */
+            if (!RtlIsNameLegalDOS8Dot3(&ustr, NULL, NULL))
+                goto notfound;
+            sp += tmplen;
+            lp += tmplen;
+            continue;
+        }
+
+        /* Check if the file exists and use the existing file name */
+        goit = FindFirstFileW(tmpshortpath, &wfd);
+        if (goit == INVALID_HANDLE_VALUE) goto notfound;
+        FindClose(goit);
+        strcpyW(tmpshortpath + sp, wfd.cAlternateFileName);
+        sp += strlenW(tmpshortpath + sp);
+        lp += tmplen;
+    }
+    tmpshortpath[sp] = 0;
+
+    tmplen = strlenW(tmpshortpath) + 1;
+    if (tmplen <= shortlen)
+    {
+        strcpyW(shortpath, tmpshortpath);
+        TRACE("returning %s\n", debugstr_w(shortpath));
+        tmplen--; /* length without 0 */
+    }
+
+    return tmplen;
+
+ notfound:
+    TRACE("not found!\n" );
+    SetLastError ( ERROR_FILE_NOT_FOUND );
+    return 0;
+}
+
+/***********************************************************************
+ *           GetShortPathNameA   (KERNEL32.@)
+ */
+DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen )
+{
+    UNICODE_STRING longpathW;
+    WCHAR shortpathW[MAX_PATH];
+    DWORD ret, retW;
+
+    if (!longpath)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+
+    TRACE("%s\n", debugstr_a(longpath));
+
+    if (!RtlCreateUnicodeStringFromAsciiz(&longpathW, longpath))
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return 0;
+    }
+
+    retW = GetShortPathNameW(longpathW.Buffer, shortpathW, MAX_PATH);
+
+    if (!retW)
+        ret = 0;
+    else if (retW > MAX_PATH)
+    {
+        SetLastError(ERROR_FILENAME_EXCED_RANGE);
+        ret = 0;
+    }
+    else
+    {
+        ret = WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, NULL, 0, NULL, NULL);
+        if (ret <= shortlen)
+        {
+            WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, shortpath, shortlen, NULL, NULL);
+            ret--; /* length without 0 */
+        }
+    }
+
+    RtlFreeUnicodeString(&longpathW);
+    return ret;
+}
+
+
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel38/tests/path.c dlls/kernel/tests/path.c
--- dlls/kernel38/tests/path.c	2003-12-06 16:08:32.000000000 +0100
+++ dlls/kernel/tests/path.c	2003-12-13 10:53:55.000000000 +0100
@@ -112,14 +112,11 @@
   len=GetFullPathNameA(subpath,MAX_PATH,tmpstr,&strptr);
   ok(len, "GetFullPathNameA failed for: '%s'",subpath);
   if(HAS_TRAIL_SLASH_A(subpath)) {
-/* Wine strips off the trailing '\\'. Neither Win98 nor Win2k do this. */
-    todo_wine {
-      ok(strptr==NULL,
-         "%s: GetFullPathNameA should not return a filename ptr",errstr);
-      ok(lstrcmpiA(fullpath,tmpstr)==0,
-         "%s: GetFullPathNameA returned '%s' instead of '%s'",
-         errstr,tmpstr,fullpath);
-    }
+    ok(strptr==NULL,
+       "%s: GetFullPathNameA should not return a filename ptr %s=>%s",subpath,strptr,errstr);
+    ok(lstrcmpiA(fullpath,tmpstr)==0,
+       "%s: GetFullPathNameA returned '%s' instead of '%s'",
+       errstr,tmpstr,fullpath);
   } else {
     ok(lstrcmpiA(strptr,filename)==0,
        "%s: GetFullPathNameA returned '%s' instead of '%s'",
@@ -141,7 +138,7 @@
    We test both conversion from GetFullPathNameA and from GetShortPathNameA
 */
   if(pGetLongPathNameA) {
-    if(len==0) {
+    if(len!=0) {
       SetLastError(0);
       len=pGetLongPathNameA(shortstr,tmpstr,MAX_PATH);
       if(passfail==NULL) {
@@ -160,12 +157,9 @@
     if(passfail==NULL) {
       ok(len, "%s: GetLongPathNameA failed",errstr);
       if(HAS_TRAIL_SLASH_A(fullpath)) {
-/* Wine strips off the trailing '\\'  Neither Win98 nor Win2k do this */
-        todo_wine {
-          ok(lstrcmpiA(fullpathlong,tmpstr)==0,
+        ok(lstrcmpiA(fullpathlong,tmpstr)==0,
            "%s: GetLongPathNameA returned '%s' instead of '%s'",
            errstr,tmpstr,fullpathlong);
-        }
       } else {
         ok(lstrcmpiA(fullpathlong,tmpstr)==0,
           "%s: GetLongPathNameA returned '%s' instead of '%s'",
@@ -229,7 +223,7 @@
 /* Test that Get(Short|Long|Full)PathNameA work correctly with interesting
    characters in the filename.
      'valid' indicates whether this would be an allowed filename
-     'todo' indictaes that wine doesn't get this right yet.
+     'todo' indicates that wine doesn't get this right yet.
    NOTE: We always call this routine with a non-existent filename, so
          Get(Short|Long)PathNameA should never pass, but GetFullPathNameA
          should.
@@ -518,13 +512,11 @@
        "GetLongPathNameA: wrong return code, %ld instead of %d",
        rc1, strlen(tmpstr)+1);
 
-    todo_wine {
-        sprintf(dir,"%c:",curDrive);
-        rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr));
-        ok(strcmp(dir,tmpstr)==0,
-           "GetLongPathNameA: returned '%s' instead of '%s' (rc=%ld)",
-           tmpstr,dir,rc1);
-    }
+    sprintf(dir,"%c:",curDrive);
+    rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr));
+    ok(strcmp(dir,tmpstr)==0,
+       "GetLongPathNameA: returned '%s' instead of '%s' (rc=%ld)",
+       tmpstr,dir,rc1);
   }
 
 /* Check the cases where both file and directory exist first */
@@ -773,11 +765,9 @@
   ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed");
   test_SplitShortPathA(tmpstr,dir,eight,three);
   if(pGetLongPathNameA) {
-    ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed");
-    todo_wine {
-      ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
-         "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,LONGDIR);
-    }
+    ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed");
+    ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
+       "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,LONGDIR);
   }
   sprintf(tmpstr,".\\%s",LONGDIR);
   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed");
@@ -785,11 +775,10 @@
   ok(lstrcmpiA(dir,".")==0 || dir[0]=='\0',
      "GetShortPathNameA did not keep relative directory [%s]",tmpstr1);
   if(pGetLongPathNameA) {
-    ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetShortPathNameA failed");
-    todo_wine {
-      ok(lstrcmpiA(tmpstr1,tmpstr)==0,
-         "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr);
-    }
+    ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetLongPathNameA failed %s",
+       tmpstr);
+    ok(lstrcmpiA(tmpstr1,tmpstr)==0,
+       "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr);
   }
 /* Check out Get*PathNameA on some funny characters */
   for(i=0;i<lstrlenA(funny_chars);i++) {
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll38/path.c dlls/ntdll/path.c
--- dlls/ntdll38/path.c	2003-12-06 16:08:36.000000000 +0100
+++ dlls/ntdll/path.c	2003-12-13 10:52:49.000000000 +0100
@@ -614,6 +614,7 @@
 BOOLEAN WINAPI RtlIsNameLegalDOS8Dot3( const UNICODE_STRING *unicode,
                                        OEM_STRING *oem, BOOLEAN *spaces )
 {
+    static const char* illegal = "*?<>|\"+=,;[]:/\\\345";
     int dot = -1;
     unsigned int i;
     char buffer[12];
@@ -654,7 +655,7 @@
             dot = i;
             break;
         default:
-            /* FIXME: check for invalid chars */
+            if (strchr(illegal, oem->Buffer[i])) return FALSE;
             break;
         }
     }
diff -u -N -r -x '*~' -x '.#*' -x CVS files38/dos_fs.c files/dos_fs.c
--- files38/dos_fs.c	2003-12-07 11:24:07.000000000 +0100
+++ files/dos_fs.c	2003-12-13 10:23:45.000000000 +0100
@@ -1173,527 +1173,6 @@
 
 
 /***********************************************************************
- *           GetShortPathNameW   (KERNEL32.@)
- *
- * NOTES
- *  observed:
- *  longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
- *  longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0
- *
- * more observations ( with NT 3.51 (WinDD) ):
- * longpath <= 8.3 -> just copy longpath to shortpath
- * longpath > 8.3  ->
- *             a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND
- *             b) file does exist     -> set the short filename.
- * - trailing slashes are reproduced in the short name, even if the
- *   file is not a directory
- * - the absolute/relative path of the short name is reproduced like found
- *   in the long name
- * - longpath and shortpath may have the same address
- * Peter Ganten, 1999
- */
-DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortlen )
-{
-    DOS_FULL_NAME full_name;
-    WCHAR tmpshortpath[MAX_PATHNAME_LEN];
-    const WCHAR *p;
-    DWORD sp = 0, lp = 0;
-    int drive;
-    DWORD tmplen;
-    UINT flags;
-    BOOL unixabsolute = *longpath == '/';
-
-    TRACE("%s\n", debugstr_w(longpath));
-
-    if (!longpath) {
-      SetLastError(ERROR_INVALID_PARAMETER);
-      return 0;
-    }
-    if (!longpath[0]) {
-      SetLastError(ERROR_BAD_PATHNAME);
-      return 0;
-    }
-
-    /* check for drive letter */
-    if (!unixabsolute && longpath[1] == ':' ) {
-      tmpshortpath[0] = longpath[0];
-      tmpshortpath[1] = ':';
-      sp = 2;
-    }
-
-    if ( ( drive = DOSFS_GetPathDrive ( &longpath )) == -1 ) return 0;
-    flags = DRIVE_GetFlags ( drive );
-
-    if (unixabsolute && drive != DRIVE_GetCurrentDrive()) {
-      tmpshortpath[0] = drive + 'A';
-      tmpshortpath[1] = ':';
-      sp = 2;
-    }
-
-    while ( longpath[lp] ) {
-
-      /* check for path delimiters and reproduce them */
-      if ( longpath[lp] == '\\' || longpath[lp] == '/' ) {
-	if (!sp || tmpshortpath[sp-1]!= '\\')
-        {
-	    /* strip double "\\" */
-	    tmpshortpath[sp] = '\\';
-	    sp++;
-        }
-        tmpshortpath[sp]=0;/*terminate string*/
-	lp++;
-	continue;
-      }
-
-      tmplen = 0;
-      for(p = longpath + lp; *p && *p != '/' && *p != '\\'; p++)
-          tmplen++;
-      lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1);
-
-      /* Check, if the current element is a valid dos name */
-      if ( DOSFS_ValidDOSName ( longpath + lp, !(flags & DRIVE_CASE_SENSITIVE) ) ) {
-	sp += tmplen;
-	lp += tmplen;
-	continue;
-      }
-
-      /* Check if the file exists and use the existing file name */
-      if ( DOSFS_GetFullName ( tmpshortpath, TRUE, &full_name ) ) {
-	strcpyW(tmpshortpath + sp, strrchrW(full_name.short_name, '\\') + 1);
-	sp += strlenW(tmpshortpath + sp);
-	lp += tmplen;
-	continue;
-      }
-
-      TRACE("not found!\n" );
-      SetLastError ( ERROR_FILE_NOT_FOUND );
-      return 0;
-    }
-    tmpshortpath[sp] = 0;
-
-    tmplen = strlenW(tmpshortpath) + 1;
-    if (tmplen <= shortlen)
-    {
-        strcpyW(shortpath, tmpshortpath);
-        TRACE("returning %s\n", debugstr_w(shortpath));
-        tmplen--; /* length without 0 */
-    }
-
-    return tmplen;
-}
-
-
-/***********************************************************************
- *           GetShortPathNameA   (KERNEL32.@)
- */
-DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen )
-{
-    UNICODE_STRING longpathW;
-    WCHAR shortpathW[MAX_PATH];
-    DWORD ret, retW;
-
-    if (!longpath)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    TRACE("%s\n", debugstr_a(longpath));
-
-    if (!RtlCreateUnicodeStringFromAsciiz(&longpathW, longpath))
-    {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return 0;
-    }
-
-    retW = GetShortPathNameW(longpathW.Buffer, shortpathW, MAX_PATH);
-
-    if (!retW)
-        ret = 0;
-    else if (retW > MAX_PATH)
-    {
-        SetLastError(ERROR_FILENAME_EXCED_RANGE);
-        ret = 0;
-    }
-    else
-    {
-        ret = WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, NULL, 0, NULL, NULL);
-        if (ret <= shortlen)
-        {
-            WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, shortpath, shortlen, NULL, NULL);
-            ret--; /* length without 0 */
-        }
-    }
-
-    RtlFreeUnicodeString(&longpathW);
-    return ret;
-}
-
-
-/***********************************************************************
- *           GetLongPathNameW   (KERNEL32.@)
- *
- * NOTES
- *  observed (Win2000):
- *  shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
- *  shortpath="":   LastError=ERROR_PATH_NOT_FOUND, ret=0
- */
-DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen )
-{
-    DOS_FULL_NAME full_name;
-    const char *root;
-    LPWSTR p;
-    int drive;
-    DWORD ret, len = 0;
-
-    if (!shortpath) {
-      SetLastError(ERROR_INVALID_PARAMETER);
-      return 0;
-    }
-    if (!shortpath[0]) {
-      SetLastError(ERROR_PATH_NOT_FOUND);
-      return 0;
-    }
-
-    TRACE("%s,%p,%ld\n", debugstr_w(shortpath), longpath, longlen);
-
-    if(shortpath[0]=='\\' && shortpath[1]=='\\')
-    {
-        ERR("UNC pathname %s\n",debugstr_w(shortpath));
-        lstrcpynW( longpath, full_name.short_name, longlen );
-        return strlenW(longpath);
-    }
-
-    if (!DOSFS_GetFullName( shortpath, TRUE, &full_name )) return 0;
-
-    root = full_name.long_name;
-    drive = DRIVE_FindDriveRoot(&root);
-
-    ret = MultiByteToWideChar(CP_UNIXCP, 0, root, -1, NULL, 0);
-    ret += 3; /* A:\ */
-    /* reproduce terminating slash */
-    if (ret > 4) /* if not drive root */
-    {
-        len = strlenW(shortpath);
-        if (shortpath[len - 1] == '\\' || shortpath[len - 1] == '/')
-            len = 1;
-    }
-    ret += len;
-    if (ret <= longlen)
-    {
-        longpath[0] = 'A' + drive;
-        longpath[1] = ':';
-        MultiByteToWideChar(CP_UNIXCP, 0, root, -1, longpath + 2, longlen - 2);
-        for (p = longpath; *p; p++) if (*p == '/') *p = '\\';
-        if (len)
-        {
-            longpath[ret - 2] = '\\';
-            longpath[ret - 1] = 0;
-        }
-        TRACE("returning %s\n", debugstr_w(longpath));
-        ret--; /* length without 0 */
-    }
-    return ret;
-}
-
-
-/***********************************************************************
- *           GetLongPathNameA   (KERNEL32.@)
- */
-DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen )
-{
-    UNICODE_STRING shortpathW;
-    WCHAR longpathW[MAX_PATH];
-    DWORD ret, retW;
-
-    if (!shortpath)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    TRACE("%s\n", debugstr_a(shortpath));
-
-    if (!RtlCreateUnicodeStringFromAsciiz(&shortpathW, shortpath))
-    {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return 0;
-    }
-
-    retW = GetLongPathNameW(shortpathW.Buffer, longpathW, MAX_PATH);
-
-    if (!retW)
-        ret = 0;
-    else if (retW > MAX_PATH)
-    {
-        SetLastError(ERROR_FILENAME_EXCED_RANGE);
-        ret = 0;
-    }
-    else
-    {
-        ret = WideCharToMultiByte(CP_ACP, 0, longpathW, -1, NULL, 0, NULL, NULL);
-        if (ret <= longlen)
-        {
-            WideCharToMultiByte(CP_ACP, 0, longpathW, -1, longpath, longlen, NULL, NULL);
-            ret--; /* length without 0 */
-        }
-    }
-
-    RtlFreeUnicodeString(&shortpathW);
-    return ret;
-}
-
-
-/***********************************************************************
- *           DOSFS_DoGetFullPathName
- *
- * Implementation of GetFullPathNameA/W.
- *
- * bon at elektron 000331:
- * A test for GetFullPathName with many pathological cases
- * now gives identical output for Wine and OSR2
- */
-static DWORD DOSFS_DoGetFullPathName( LPCWSTR name, DWORD len, LPWSTR result )
-{
-    DWORD ret;
-    DOS_FULL_NAME full_name;
-    LPWSTR p, q;
-    char *p_l;
-    const char * root;
-    WCHAR drivecur[] = {'C',':','.',0};
-    WCHAR driveletter=0;
-    int namelen,drive=0;
-    static const WCHAR bkslashW[] = {'\\',0};
-    static const WCHAR dotW[] = {'.',0};
-    static const WCHAR updir_slashW[] = {'\\','.','.','\\',0};
-    static const WCHAR curdirW[] = {'\\','.','\\',0};
-    static const WCHAR updirW[] = {'\\','.','.',0};
-
-    if (!name[0])
-    {
-        SetLastError(ERROR_BAD_PATHNAME);
-        return 0;
-    }
-
-    TRACE("passed %s\n", debugstr_w(name));
-
-    if (name[1]==':')
-      /*drive letter given */
-      {
-	driveletter = name[0];
-      }
-    if ((name[1]==':') && ((name[2]=='\\') || (name[2]=='/')))
-      /*absolute path given */
-      {
-        strncpyW(full_name.short_name, name, MAX_PATHNAME_LEN);
-        full_name.short_name[MAX_PATHNAME_LEN - 1] = 0; /* ensure 0 termination */
-        drive = toupperW(name[0]) - 'A';
-      }
-    else
-      {
-	if (driveletter)
-	  drivecur[0]=driveletter;
-        else if ((name[0]=='\\') || (name[0]=='/'))
-          strcpyW(drivecur, bkslashW);
-        else
-	  strcpyW(drivecur, dotW);
-
-	if (!DOSFS_GetFullName( drivecur, FALSE, &full_name ))
-	  {
-	    FIXME("internal: error getting drive/path\n");
-	    return 0;
-	  }
-	/* find path that drive letter substitutes*/
-	drive = toupperW(full_name.short_name[0]) - 'A';
-	root= DRIVE_GetRoot(drive);
-	if (!root)
-	  {
-	    FIXME("internal: error getting DOS Drive Root\n");
-	    return 0;
-	  }
-	if (!strcmp(root,"/"))
-	  {
-	    /* we have just the last / and we need it. */
-	    p_l = full_name.long_name;
-	  }
-	else
-	  {
-	    p_l = full_name.long_name + strlen(root);
-	  }
-	/* append long name (= unix name) to drive */
-	MultiByteToWideChar(CP_UNIXCP, 0, p_l, -1, full_name.short_name + 2, MAX_PATHNAME_LEN - 3);
-	/* append name to treat */
-	namelen= strlenW(full_name.short_name);
-	p = (LPWSTR)name;
-	if (driveletter)
-	  p += 2; /* skip drive name when appending */
-	if (namelen + 2 + strlenW(p) > MAX_PATHNAME_LEN)
-	  {
-	    FIXME("internal error: buffer too small\n");
-	     return 0;
-	  }
-	full_name.short_name[namelen++] ='\\';
-	full_name.short_name[namelen] = 0;
-	strncpyW(full_name.short_name + namelen, p, MAX_PATHNAME_LEN - namelen);
-	full_name.short_name[MAX_PATHNAME_LEN - 1] = 0; /* ensure 0 termination */
-      }
-    /* reverse all slashes */
-    for (p=full_name.short_name;
-	 p < full_name.short_name + strlenW(full_name.short_name);
-	 p++)
-      {
-	if ( *p == '/' )
-	  *p = '\\';
-      }
-     /* Use memmove, as areas overlap */
-     /* Delete .. */
-    while ((p = strstrW(full_name.short_name, updir_slashW)))
-      {
-	if (p > full_name.short_name+2)
-	  {
-	    *p = 0;
-            q = strrchrW(full_name.short_name, '\\');
-            memmove(q+1, p+4, (strlenW(p+4)+1) * sizeof(WCHAR));
-	  }
-	else
-	  {
-            memmove(full_name.short_name+3, p+4, (strlenW(p+4)+1) * sizeof(WCHAR));
-	  }
-      }
-    if ((full_name.short_name[2]=='.')&&(full_name.short_name[3]=='.'))
-	{
-	  /* This case istn't treated yet : c:..\test */
-	  memmove(full_name.short_name+2,full_name.short_name+4,
-                  (strlenW(full_name.short_name+4)+1) * sizeof(WCHAR));
-	}
-     /* Delete . */
-    while ((p = strstrW(full_name.short_name, curdirW)))
-      {
-	*(p+1) = 0;
-        memmove(p+1, p+3, (strlenW(p+3)+1) * sizeof(WCHAR));
-      }
-    if (!(DRIVE_GetFlags(drive) & DRIVE_CASE_PRESERVING))
-        for (p = full_name.short_name; *p; p++) *p = toupperW(*p);
-    namelen = strlenW(full_name.short_name);
-    if (!strcmpW(full_name.short_name+namelen-3, updirW))
-	{
-	  /* one more strange case: "c:\test\test1\.."
-	   return "c:\test" */
-	  *(full_name.short_name+namelen-3)=0;
-          q = strrchrW(full_name.short_name, '\\');
-	  *q =0;
-	}
-    if (full_name.short_name[namelen-1]=='.')
-	full_name.short_name[(namelen--)-1] =0;
-    if (!driveletter)
-      if (full_name.short_name[namelen-1]=='\\')
-	full_name.short_name[(namelen--)-1] =0;
-    TRACE("got %s\n", debugstr_w(full_name.short_name));
-
-    /* If the lpBuffer buffer is too small, the return value is the
-    size of the buffer, in characters, required to hold the path
-    plus the terminating \0 (tested against win95osr2, bon 001118)
-    . */
-    ret = strlenW(full_name.short_name);
-    if (ret >= len )
-      {
-	/* don't touch anything when the buffer is not large enough */
-        SetLastError( ERROR_INSUFFICIENT_BUFFER );
-	return ret+1;
-      }
-    if (result)
-    {
-        strncpyW( result, full_name.short_name, len );
-        result[len - 1] = 0; /* ensure 0 termination */
-    }
-
-    TRACE("returning %s\n", debugstr_w(full_name.short_name) );
-    return ret;
-}
-
-
-/***********************************************************************
- *           GetFullPathNameA   (KERNEL32.@)
- * NOTES
- *   if the path closed with '\', *lastpart is 0
- */
-DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer,
-                                 LPSTR *lastpart )
-{
-    UNICODE_STRING nameW;
-    WCHAR bufferW[MAX_PATH];
-    DWORD ret, retW;
-
-    if (!name)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
-    }
-
-    if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name))
-    {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return 0;
-    }
-
-    retW = GetFullPathNameW( nameW.Buffer, MAX_PATH, bufferW, NULL);
-
-    if (!retW)
-        ret = 0;
-    else if (retW > MAX_PATH)
-    {
-        SetLastError(ERROR_FILENAME_EXCED_RANGE);
-        ret = 0;
-    }
-    else
-    {
-        ret = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
-        if (ret <= len)
-        {
-            WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, len, NULL, NULL);
-            ret--; /* length without 0 */
-
-            if (lastpart)
-            {
-                LPSTR p = buffer + strlen(buffer);
-
-                if (*p != '\\')
-                {
-                    while ((p > buffer + 2) && (*p != '\\')) p--;
-                    *lastpart = p + 1;
-                }
-                else *lastpart = NULL;
-            }
-        }
-    }
-
-    RtlFreeUnicodeString(&nameW);
-    return ret;
-}
-
-
-/***********************************************************************
- *           GetFullPathNameW   (KERNEL32.@)
- */
-DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer,
-                                 LPWSTR *lastpart )
-{
-    DWORD ret = DOSFS_DoGetFullPathName( name, len, buffer );
-    if (ret && (ret<=len) && buffer && lastpart)
-    {
-        LPWSTR p = buffer + strlenW(buffer);
-        if (*p != (WCHAR)'\\')
-        {
-            while ((p > buffer + 2) && (*p != (WCHAR)'\\')) p--;
-            *lastpart = p + 1;
-        }
-        else *lastpart = NULL;
-    }
-    return ret;
-}
-
-
-/***********************************************************************
  *           wine_get_unix_file_name (KERNEL32.@) Not a Windows API
  *
  * Return the full Unix file name for a given path.


More information about the wine-patches mailing list