ntdll / kernel32: #39-2

Eric Pouech pouech-eric at wanadoo.fr
Sun Jan 18 08:06:15 CST 2004


Resending to include various clean-up:s
- ntdll.RtlGetFullPathName_U: rewritten so that the source & destination 
buffer can be the same
- kernel32.GetFullPathName[AW]: now call ntdll.RtlGetFullPathName_U
- kernel32.GetShortPathNameW: fixed regression introduced in last patch
A+
-------------- next part --------------
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel38/path.c dlls/kernel/path.c
--- dlls/kernel38/path.c	2004-01-15 01:20:46.000000000 +0100
+++ dlls/kernel/path.c	2004-01-18 11:26:12.000000000 +0100
@@ -42,6 +42,76 @@
 
 #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 )
+{
+    return RtlGetFullPathName_U(name, len * sizeof(WCHAR), buffer, lastpart) / sizeof(WCHAR);
+}
+
+/***********************************************************************
+ *           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.@)
@@ -266,20 +336,21 @@
         for (p = longpath + lp; *p && *p != '/' && *p != '\\'; p++);
         tmplen = p - (longpath + lp);
         lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1);
+        /* Check, if the current element is a valid dos name */
         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;
+            if (RtlIsNameLegalDOS8Dot3(&ustr, NULL, NULL))
+            {
+                sp += tmplen;
+                lp += tmplen;
+                continue;
+            }
         }
 
-        /* Check if the file exists and use the existing file name */
+        /* Check if the file exists and use the existing short file name */
         goit = FindFirstFileW(tmpshortpath, &wfd);
         if (goit == INVALID_HANDLE_VALUE) goto notfound;
         FindClose(goit);
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll38/path.c dlls/ntdll/path.c
--- dlls/ntdll38/path.c	2004-01-17 08:09:22.000000000 +0100
+++ dlls/ntdll/path.c	2004-01-18 12:02:26.000000000 +0100
@@ -281,13 +281,13 @@
             for (needed = 0, ptr = paths; *ptr != 0 && *ptr++ != ';'; needed++);
             if (needed + filelen > allocated)
             {
-                if (!name) name = RtlAllocateHeap(GetProcessHeap(), 0,
+                if (!name) name = RtlAllocateHeap(ntdll_get_process_heap(), 0,
                                                   (needed + filelen) * sizeof(WCHAR));
                 else
                 {
-                    WCHAR *newname = RtlReAllocateHeap(GetProcessHeap(), 0, name,
+                    WCHAR *newname = RtlReAllocateHeap(ntdll_get_process_heap(), 0, name,
                                                        (needed + filelen) * sizeof(WCHAR));
-                    if (!newname) RtlFreeHeap(GetProcessHeap(), 0, name);
+                    if (!newname) RtlFreeHeap(ntdll_get_process_heap(), 0, name);
                     name = newname;
                 }
                 if (!name) return 0;
@@ -319,55 +319,50 @@
  *		get_full_path_helper
  *
  * Helper for RtlGetFullPathName_U
+ * Note: name and buffer are allowed to point to the same memory spot
  */
 static ULONG get_full_path_helper(LPCWSTR name, LPWSTR buffer, ULONG size)
 {
-    ULONG               reqsize, mark = 0;
-    DOS_PATHNAME_TYPE   type;
-    LPWSTR              ptr;
-    UNICODE_STRING*     cd;
-
-    reqsize = sizeof(WCHAR); /* '\0' at the end */
-
+    ULONG                       reqsize = 0, mark = 0, dep = 0, deplen;
+    DOS_PATHNAME_TYPE           type;
+    LPWSTR                      ptr, ins_str = NULL;
+    const UNICODE_STRING*       cd;
+    WCHAR                       tmp[4];
+    
     RtlAcquirePebLock();
+
     cd = &ntdll_get_process_pmts()->CurrentDirectoryName;
 
     switch (type = RtlDetermineDosPathNameType_U(name))
     {
     case UNC_PATH:              /* \\foo   */
     case DEVICE_PATH:           /* \\.\foo */
-        if (reqsize <= size) buffer[0] = '\0';
         break;
 
     case ABSOLUTE_DRIVE_PATH:   /* c:\foo  */
-        reqsize += sizeof(WCHAR);
-        if (reqsize <= size)
-        {
-            buffer[0] = toupperW(name[0]);
-            buffer[1] = '\0';
-        }
-        name++;
+        reqsize = sizeof(WCHAR);
+        tmp[0] = toupperW(name[0]);
+        ins_str = tmp;
+        dep = 1;
         break;
 
     case RELATIVE_DRIVE_PATH:   /* c:foo   */
+        dep = 2;
         if (toupperW(name[0]) != toupperW(cd->Buffer[0]) || cd->Buffer[1] != ':')
         {
-            WCHAR               drive[4];
             UNICODE_STRING      var, val;
 
-            drive[0] = '=';
-            drive[1] = name[0];
-            drive[2] = ':';
-            drive[3] = '\0';
-            var.Length = 6;
-            var.MaximumLength = 8;
-            var.Buffer = drive;
+            tmp[0] = '=';
+            tmp[1] = name[0];
+            tmp[2] = ':';
+            tmp[3] = '\0';
+            var.Length = 3 * sizeof(WCHAR);
+            var.MaximumLength = 4 * sizeof(WCHAR);
+            var.Buffer = tmp;
             val.Length = 0;
             val.MaximumLength = size;
-            val.Buffer = buffer;
-
-            name += 2;
-
+            val.Buffer = RtlAllocateHeap(ntdll_get_process_heap(), 0, size);
+            
             switch (RtlQueryEnvironmentVariable_U(NULL, &var, &val))
             {
             case STATUS_SUCCESS:
@@ -378,24 +373,16 @@
                  */
                 /* fall thru */
             case STATUS_BUFFER_TOO_SMALL:
-                reqsize += val.Length;
-                /* append trailing \\ */
-                reqsize += sizeof(WCHAR);
-                if (reqsize <= size)
-                {
-                    buffer[reqsize / sizeof(WCHAR) - 2] = '\\';
-                    buffer[reqsize / sizeof(WCHAR) - 1] = '\0';
-                }
+                reqsize = val.Length + sizeof(WCHAR); /* append trailing '\\' */
+                val.Buffer[val.Length / sizeof(WCHAR)] = '\\';
+                ins_str = val.Buffer;
                 break;
             case STATUS_VARIABLE_NOT_FOUND:
-                reqsize += 3 * sizeof(WCHAR);
-                if (reqsize <= size)
-                {
-                    buffer[0] = drive[1];
-                    buffer[1] = ':';
-                    buffer[2] = '\\';
-                    buffer[3] = '\0';
-                }
+                reqsize = 3 * sizeof(WCHAR);
+                tmp[0] = name[0];
+                tmp[1] = ':';
+                tmp[2] = '\\';
+                ins_str = tmp;
                 break;
             default:
                 ERR("Unsupported status code\n");
@@ -403,16 +390,11 @@
             }
             break;
         }
-        name += 2;
         /* fall through */
 
     case RELATIVE_PATH:         /* foo     */
-        reqsize += cd->Length;
-        if (reqsize <= size)
-        {
-            memcpy(buffer, cd->Buffer, cd->Length);
-            buffer[cd->Length / sizeof(WCHAR)] = 0;
-        }
+        reqsize = cd->Length;
+        ins_str = cd->Buffer;
         if (cd->Buffer[1] != ':')
         {
             ptr = strchrW(cd->Buffer + 2, '\\');
@@ -425,69 +407,62 @@
     case ABSOLUTE_PATH:         /* \xxx    */
         if (cd->Buffer[1] == ':')
         {
-            reqsize += 2 * sizeof(WCHAR);
-            if (reqsize <= size)
-            {
-                buffer[0] = cd->Buffer[0];
-                buffer[1] = ':';
-                buffer[2] = '\0';
-            }
+            reqsize = 2 * sizeof(WCHAR);
+            tmp[0] = cd->Buffer[0];
+            tmp[1] = ':';
+            ins_str = tmp;
         }
         else
         {
-            unsigned    len;
-
             ptr = strchrW(cd->Buffer + 2, '\\');
             if (ptr) ptr = strchrW(ptr + 1, '\\');
             if (!ptr) ptr = cd->Buffer + strlenW(cd->Buffer);
-            len = (ptr - cd->Buffer) * sizeof(WCHAR);
-            reqsize += len;
-            mark = len / sizeof(WCHAR);
-            if (reqsize <= size)
-            {
-                memcpy(buffer, cd->Buffer, len);
-                buffer[len / sizeof(WCHAR)] = '\0';
-            }
-            else
-                buffer[0] = '\0';
+            reqsize = (ptr - cd->Buffer) * sizeof(WCHAR);
+            mark = reqsize / sizeof(WCHAR);
+            ins_str = cd->Buffer;
         }
         break;
 
     case UNC_DOT_PATH:         /* \\.     */
-        reqsize += 4 * sizeof(WCHAR);
-        name += 3;
-        if (reqsize <= size)
-        {
-            buffer[0] = '\\';
-            buffer[1] = '\\';
-            buffer[2] = '.';
-            buffer[3] = '\\';
-            buffer[4] = '\0';
-        }
+        reqsize = 4 * sizeof(WCHAR);
+        dep = 3;
+        tmp[0] = '\\';
+        tmp[1] = '\\';
+        tmp[2] = '.';
+        tmp[3] = '\\';
+        ins_str = tmp;
         break;
 
     case INVALID_PATH:
-        reqsize = 0;
         goto done;
     }
 
-    reqsize += strlenW(name) * sizeof(WCHAR);
-    if (reqsize > size) goto done;
+    /* enough space ? */
+    deplen = strlenW(name + dep) * sizeof(WCHAR);
+    if (reqsize + deplen + sizeof(WCHAR) > size)
+    {
+        /* not enough space, return need size (including terminating '\0') */
+        reqsize += deplen + sizeof(WCHAR);
+        goto done;
+    }
 
-    strcatW(buffer, name);
+    memmove(buffer + reqsize / sizeof(WCHAR), name + dep, deplen + sizeof(WCHAR));
+    if (reqsize) memcpy(buffer, ins_str, reqsize);
+    reqsize += deplen;
 
-    /* convert every / into a \ */
-    for (ptr = buffer; *ptr; ptr++)
-        if (*ptr == '/') *ptr = '\\';
+    if (ins_str && ins_str != tmp && ins_str != cd->Buffer)
+        RtlFreeHeap(ntdll_get_process_heap(), 0, ins_str);
 
-    reqsize -= sizeof(WCHAR); /* don't count trailing \0 */
+    /* convert every / into a \ */
+    for (ptr = buffer; *ptr; ptr++) if (*ptr == '/') *ptr = '\\';
 
     /* mark is non NULL for UNC names, so start path collapsing after server & share name
      * otherwise, it's a fully qualified DOS name, so start after the drive designation
      */
     for (ptr = buffer + (mark ? mark : 2); ptr < buffer + reqsize / sizeof(WCHAR); )
     {
-        WCHAR* p = strchrW(ptr, '\\');
+        LPWSTR  prev, p = strchrW(ptr, '\\');
+
         if (!p) break;
 
         p++;
@@ -499,15 +474,13 @@
                 switch (p[2])
                 {
                 case '\\':
-                    {
-                        WCHAR*      prev = p - 2;
-                        while (prev >= buffer + mark && *prev != '\\') prev--;
-                        /* either collapse \foo\.. into \ or \.. into \ */
-                        if (prev < buffer + mark) prev = p - 1;
-                        reqsize -= (p + 2 - prev) * sizeof(WCHAR);
-                        memmove(prev, p + 2, reqsize + sizeof(WCHAR) - (prev - buffer) * sizeof(WCHAR));
-                        p = prev;
-                    }
+                    prev = p - 2;
+                    while (prev >= buffer + mark && *prev != '\\') prev--;
+                    /* either collapse \foo\.. into \ or \.. into \ */
+                    if (prev < buffer + mark) prev = p - 1;
+                    reqsize -= (p + 2 - prev) * sizeof(WCHAR);
+                    memmove(prev, p + 2, reqsize + sizeof(WCHAR) - (prev - buffer) * sizeof(WCHAR));
+                    p = prev;
                     break;
                 case '\0':
                     reqsize -= 2 * sizeof(WCHAR);
diff -u -N -r -x '*~' -x '.#*' -x CVS files38/dos_fs.c files/dos_fs.c
--- files38/dos_fs.c	2004-01-17 08:09:22.000000000 +0100
+++ files/dos_fs.c	2004-01-16 20:54:59.000000000 +0100
@@ -1173,252 +1173,6 @@
 
 
 /***********************************************************************
- *           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;
-    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) - 1;
-
-                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) - 1;
-        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