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