Index: lib/rtl/path.c =================================================================== --- lib/rtl/path.c (révision 59197) +++ lib/rtl/path.c (copie de travail) @@ -141,7 +141,7 @@ { /* Stop if we hit something else than a space or period */ c = PathCopy.Buffer[PathChars - 1]; - if ((c != '.') && (c != ' ')) break; + if ((c != L'.') && (c != L' ')) break; /* Fixup the lengths */ PathCopy.Length -= sizeof(WCHAR); @@ -160,7 +160,7 @@ { /* Check if the character is a path or drive separator */ c = *End; - if (IS_PATH_SEPARATOR(c) || ((c == ':') && (End == PathCopy.Buffer + 1))) + if (IS_PATH_SEPARATOR(c) || ((c == L':') && (End == PathCopy.Buffer + 1))) { /* Get the next lower case character */ End++; @@ -168,7 +168,7 @@ /* Check if it's a DOS device (LPT, COM, PRN, AUX, or NUL) */ if ((End < &PathCopy.Buffer[OriginalLength / sizeof(WCHAR)]) && - ((c == 'l') || (c == 'c') || (c == 'p') || (c == 'a') || (c == 'n'))) + ((c == L'l') || (c == L'c') || (c == L'p') || (c == L'a') || (c == L'n'))) { /* Calculate the offset */ ReturnOffset = (USHORT)((PCHAR)End - (PCHAR)PathCopy.Buffer); @@ -191,7 +191,7 @@ /* Get the next lower case character and check if it's a DOS device */ c = RtlDowncaseUnicodeChar(*PathCopy.Buffer); - if ((c != 'l') && (c != 'c') && (c != 'p') && (c != 'a') && (c != 'n')) + if ((c != L'l') && (c != L'c') && (c != L'p') && (c != L'a') && (c != L'n')) { /* Not LPT, COM, PRN, AUX, or NUL */ return 0; @@ -204,12 +204,12 @@ while (Start < End) { c = *Start; - if ((c == '.') || (c == ':')) break; + if ((c == L'.') || (c == L':')) break; Start++; } /* And then go backwards to get rid of spaces */ - while ((Start > PathCopy.Buffer) && (Start[-1] == ' ')) --Start; + while ((Start > PathCopy.Buffer) && (Start[-1] == L' ')) --Start; /* Finally see how many characters are left, and that's our size */ PathChars = (USHORT)(Start - PathCopy.Buffer); @@ -217,7 +217,7 @@ /* Check if this is a COM or LPT port, which has a digit after it */ if ((PathChars == 4) && - (iswdigit(PathCopy.Buffer[3]) && (PathCopy.Buffer[3] != '0'))) + (iswdigit(PathCopy.Buffer[3]) && (PathCopy.Buffer[3] != L'0'))) { /* Don't compare the number part, just check for LPT or COM */ PathCopy.Length -= sizeof(WCHAR); @@ -284,6 +284,360 @@ return Status; } + + + + +/****************************************************************************** + ** ** + ** WARNING !! WINE CODE FOLLOWS !! ** + ** ** + ******************************************************************************/ + +/****************************************************************** + * RtlpCollapsePath + * + * Helper for RtlGetFullPathName_U. + * 1) Convert slashes into backslashes + * 2) Get rid of duplicate backslashes + * 3) Get rid of . and .. components in the path. + */ +VOID RtlpCollapsePath(PWSTR path, UINT mark, BOOLEAN SkipTrailingPathSeparators) +{ + PWSTR p, next; + + /* convert every / into a \ */ + for (p = path; *p; p++) + { + if (*p == L'/') *p = L'\\'; + } + + /* collapse duplicate backslashes */ + next = path + max( 1, mark ); + for (p = next; *p; p++) + { + if (*p != L'\\' || next[-1] != L'\\') *next++ = *p; + } + *next = 0; + + p = path + mark; + while (*p) + { + if (*p == L'.') + { + switch(p[1]) + { + case L'\\': /* .\ component */ + next = p + 2; + RtlMoveMemory( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); + continue; + case UNICODE_NULL: /* final . */ + if (p > path + mark) p--; + *p = UNICODE_NULL; + continue; + case L'.': + if (p[2] == L'\\') /* ..\ component */ + { + next = p + 3; + if (p > path + mark) + { + p--; + while (p > path + mark && p[-1] != L'\\') p--; + } + RtlMoveMemory( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); + continue; + } + else if (!p[2]) /* final .. */ + { + if (p > path + mark) + { + p--; + while (p > path + mark && p[-1] != L'\\') p--; + if (p > path + mark) p--; + } + *p = UNICODE_NULL; + continue; + } + break; + } + } + /* skip to the next component */ + while (*p && *p != L'\\') p++; + if (*p == L'\\') + { + /* remove last dot in previous dir name */ + if (p > path + mark && p[-1] == L'.') + RtlMoveMemory( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) ); + else + p++; + } + } + + /* Remove trailing backslashes if needed */ + if (SkipTrailingPathSeparators) + { + while (p > path + mark && IS_PATH_SEPARATOR(p[-1])) *p-- = UNICODE_NULL; + } + + /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */ + while (p > path + mark && (p[-1] == L' ' || p[-1] == L'.')) *p-- = UNICODE_NULL; + + /* Null-terminate the string */ + *p = UNICODE_NULL; +} + +/****************************************************************** + * RtlpSkipUNCPrefix + * + * Helper for RtlGetFullPathName_U + * Skip the \\share\dir\ part of a file name and return the new position + */ +static SIZE_T RtlpSkipUNCPrefix(PCWSTR ptr) +{ + PCWSTR ptr2 = ptr + 2; + + while (*ptr2 && !IS_PATH_SEPARATOR(*ptr2)) ptr2++; /* share name */ + while (IS_PATH_SEPARATOR(*ptr2)) ptr2++; + while (*ptr2 && !IS_PATH_SEPARATOR(*ptr2)) ptr2++; /* dir name */ + while (IS_PATH_SEPARATOR(*ptr2)) ptr2++; + + return (ptr2 - ptr); +} + +/****************************************************************** + * RtlpGetFullPath + * + * Helper for RtlGetFullPathName_U + * Note: name and buffer are allowed to point to the same memory spot + */ +static ULONG RtlpGetFullPath( + PCWSTR name, + RTL_PATH_TYPE PathType, + PWSTR buffer, + ULONG size, + BOOLEAN SkipTrailingPathSeparators, + PCWSTR *ShortName) +{ + SIZE_T reqsize = 0, mark = 0, dep = 0, deplen; + PWSTR ins_str = NULL; + PCWSTR ptr; + PCUNICODE_STRING CurDirName; + WCHAR tmp[4] = {UNICODE_NULL}; + + /* Lock the PEB to get the current directory */ + RtlAcquirePebLock(); + CurDirName = &NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath; + + /* + * The following variables are used: + * + * mark == zero-based index of where the path (without the old prefix) starts (== length in characters of the old prefix) + * dep == length (in characters) of a new computed drive letter + * ins_str == pointer to the string to be inserted as the new path prefix + * reqsize == mostly used as the length of ins_str in bytes (at the end of the routine it is used as the required size) + */ + switch (PathType) + { + case RtlPathTypeUncAbsolute: /* \\foo */ + mark = RtlpSkipUNCPrefix(name); + break; + + case RtlPathTypeLocalDevice: /* \\.\foo */ + mark = 4; + break; + + case RtlPathTypeDriveAbsolute: /* c:\foo */ + ASSERT(name[1] == L':'); + ASSERT(name[2] == L'\\' || name[2] == L'/'); + // reqsize = sizeof(WCHAR); + // tmp[0] = RtlUpcaseUnicodeChar(name[0]); + // ins_str = tmp; + // dep = 1; + + reqsize = 3*sizeof(WCHAR); + tmp[0] = RtlUpcaseUnicodeChar(name[0]); + tmp[1] = L':'; + tmp[2] = L'\\'; + tmp[3] = UNICODE_NULL; + ins_str = tmp; + dep = 3; + + mark = 3; + break; + + case RtlPathTypeDriveRelative: /* c:foo */ + dep = 2; + if (RtlUpcaseUnicodeChar(name[0]) != RtlUpcaseUnicodeChar(CurDirName->Buffer[0]) || + CurDirName->Buffer[1] != L':') + { + UNICODE_STRING EnvVarName, EnvVarValue; + + tmp[0] = L'='; + tmp[1] = name[0]; + tmp[2] = L':'; + tmp[3] = UNICODE_NULL; + + EnvVarName.Length = 3 * sizeof(WCHAR); + EnvVarName.MaximumLength = EnvVarName.Length + sizeof(WCHAR); + EnvVarName.Buffer = tmp; + + // RtlInitEmptyUnicodeString(&EnvVarValue, NULL, size); + EnvVarValue.Length = 0; + EnvVarValue.MaximumLength = (USHORT)size; + EnvVarValue.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, size); + if (EnvVarValue.Buffer == NULL) + { + reqsize = 0; + goto Quit; + } + + switch (RtlQueryEnvironmentVariable_U(NULL, &EnvVarName, &EnvVarValue)) + { + case STATUS_SUCCESS: + /* + * (From Wine) + * FIXME: Win2k seems to check that the environment + * variable actually points to an existing directory. + * If not, root of the drive is used (this seems also + * to be the only spot in RtlGetFullPathName that the + * existence of a part of a path is checked). + */ + + /* Fall through */ + + case STATUS_BUFFER_TOO_SMALL: + reqsize = EnvVarValue.Length + sizeof(WCHAR); /* append trailing '\\' */ + EnvVarValue.Buffer[EnvVarValue.Length / sizeof(WCHAR)] = L'\\'; + ins_str = EnvVarValue.Buffer; + break; + + case STATUS_VARIABLE_NOT_FOUND: + reqsize = 3 * sizeof(WCHAR); + tmp[0] = name[0]; + tmp[1] = L':'; + tmp[2] = L'\\'; + tmp[3] = UNICODE_NULL; + ins_str = tmp; + RtlFreeHeap(RtlGetProcessHeap(), 0, EnvVarValue.Buffer); + break; + + default: + DPRINT1("Unsupported status code\n"); + RtlFreeHeap(RtlGetProcessHeap(), 0, EnvVarValue.Buffer); + break; + } + mark = 3; + break; + } + /* fall through */ + + case RtlPathTypeRelative: /* foo */ + reqsize = CurDirName->Length; + ins_str = CurDirName->Buffer; + if (CurDirName->Buffer[1] != L':') + { + mark = RtlpSkipUNCPrefix(CurDirName->Buffer); + } + else + { + mark = 3; + } + break; + + case RtlPathTypeRooted: /* \xxx */ + if (CurDirName->Buffer[1] == L':') + { + ASSERT(CurDirName->Buffer[1] == L':'); + ASSERT(CurDirName->Buffer[2] == L'\\' || CurDirName->Buffer[2] == L'/'); + + reqsize = 2 * sizeof(WCHAR); + tmp[0] = CurDirName->Buffer[0]; + tmp[1] = L':'; + ins_str = tmp; + mark = 3; + } + else + { + mark = RtlpSkipUNCPrefix(CurDirName->Buffer); + reqsize = mark * sizeof(WCHAR); + ins_str = CurDirName->Buffer; + } + break; + + case RtlPathTypeRootLocalDevice: /* \\. */ + reqsize = 4 * sizeof(WCHAR); + dep = 3; + tmp[0] = L'\\'; + tmp[1] = L'\\'; + tmp[2] = L'.'; + tmp[3] = L'\\'; + ins_str = tmp; + mark = 4; + break; + + case RtlPathTypeUnknown: + goto Quit; + } + + /* Do we have enough space for storing the full path? */ + deplen = wcslen(name + dep) * sizeof(WCHAR); + if (reqsize + deplen + sizeof(WCHAR) > size) + { + /* Not enough space, return needed size (including terminating '\0') */ + reqsize += deplen + sizeof(WCHAR); + goto Quit; + } + + /* Build the full path */ + if (ShortName) DPRINT1("buffer(1) = %S\n", buffer); + /* Copy the path's prefix */ + if (reqsize) RtlMoveMemory(buffer, ins_str, reqsize); + if (ShortName) DPRINT1("buffer(2) = %S\n", buffer); + /* Copy the remaining part of the path */ + RtlMoveMemory(buffer + reqsize / sizeof(WCHAR), name + dep, deplen + sizeof(WCHAR)); + if (ShortName) DPRINT1("buffer(3) = %S\n", buffer); + + if (ins_str && ins_str != tmp && ins_str != CurDirName->Buffer) + RtlFreeHeap(RtlGetProcessHeap(), 0, ins_str); + + /* + * Finally, put the path in canonical form, + * i.e. simplify redundant . and .., etc... + */ + RtlpCollapsePath(buffer, (UINT)mark, SkipTrailingPathSeparators); + if (ShortName) DPRINT1("buffer(4) = %S\n", buffer); + + /* Get the length of the full path name, without its terminating null character */ + reqsize = wcslen(buffer) * sizeof(WCHAR); + + /* Find the file part, which is present after the last path separator */ + if (ShortName) + { + ptr = wcsrchr(buffer, L'\\'); + if (ptr) ++ptr; // Skip it + + /* + * For UNC paths, the file part is after the \\share\dir\ part of the path. + */ + mark = (PathType == RtlPathTypeUncAbsolute ? mark : 3); + + if (ptr && *ptr && (ptr >= buffer + mark)) + { + *ShortName = ptr; + } + else + { + /* Zero-out the short name */ + *ShortName = NULL; + } + } + +Quit: + /* Release PEB lock */ + RtlReleasePebLock(); + return (ULONG)reqsize; +} + ULONG NTAPI RtlGetFullPathName_Ustr( @@ -296,6 +650,7 @@ { PWCHAR FileNameBuffer; ULONG FileNameLength, FileNameChars, DosLength, DosLengthOffset, FullLength; + BOOLEAN SkipTrailingPathSeparators; WCHAR c; NTSTATUS Status; @@ -306,29 +661,38 @@ /* Handle initial path type and failure case */ *PathType = RtlPathTypeUnknown; - if (!(FileName->Length) || (FileName->Buffer[0] == UNICODE_NULL)) return 0; + if ((FileName->Length == 0) || (FileName->Buffer[0] == UNICODE_NULL)) return 0; /* Break filename into component parts */ FileNameBuffer = FileName->Buffer; FileNameLength = FileName->Length; - FileNameChars = FileNameLength / sizeof(WCHAR); + FileNameChars = FileNameLength / sizeof(WCHAR); /* Kill trailing spaces */ c = FileNameBuffer[FileNameChars - 1]; - while ((FileNameLength) && (c == L' ')) + while ((FileNameLength != 0) && (c == L' ')) { /* Keep going, ignoring the spaces */ FileNameLength -= sizeof(WCHAR); - if (FileNameLength) c = FileNameBuffer[FileNameLength / sizeof(WCHAR) - 1]; + if (FileNameLength != 0) c = FileNameBuffer[FileNameLength / sizeof(WCHAR) - 1]; } /* Check if anything is left */ - if (!FileNameLength) return 0; + if (FileNameLength == 0) return 0; + /* + * Check whether we'll need to skip trailing path separators in the + * computed full path name. If the original file name already contained + * trailing separators, then we keep them in the full path name. On the + * other hand, if the original name didn't contain any trailing separators + * then we'll skip it in the full path name. + */ + SkipTrailingPathSeparators = !IS_PATH_SEPARATOR(FileNameBuffer[FileNameChars - 1]); + /* Check if this is a DOS name */ DosLength = RtlIsDosDeviceName_Ustr(FileName); DPRINT("DOS length for filename: %lx %wZ\n", DosLength, FileName); - if (DosLength) + if (DosLength != 0) { /* Zero out the short name */ if (ShortName) *ShortName = NULL; @@ -336,9 +700,11 @@ /* See comment for RtlIsDosDeviceName_Ustr if this is confusing... */ DosLengthOffset = DosLength >> 16; DosLength = DosLength & 0xFFFF; + // DWORD offset = HIWORD(dosdev) / sizeof(WCHAR); /* get it in WCHARs, not bytes */ + // DWORD sz = LOWORD(dosdev); /* in bytes */ /* Do we have a DOS length, and does the caller want validity? */ - if ((InvalidName) && (DosLengthOffset)) + if (InvalidName && (DosLengthOffset != 0)) { /* Do the check */ Status = RtlpCheckDeviceName(FileName, DosLengthOffset, InvalidName); @@ -370,13 +736,17 @@ return FullLength + sizeof(UNICODE_NULL); } - /* This should work well enough for our current needs */ + /* Zero out the destination buffer. FileName must be different from Buffer */ + RtlZeroMemory(Buffer, Size); + + /* Get the path type */ *PathType = RtlDetermineDosPathNameType_U(FileNameBuffer); - DPRINT("Path type: %lx\n", *PathType); - /* This is disgusting... but avoids re-writing everything */ - DPRINT("Calling old API with '%S' and %lu and %S\n", FileNameBuffer, Size, Buffer); - return RtlGetFullPathName_U(FileNameBuffer, Size, Buffer, (PWSTR*)ShortName); + /********************************************** + ** HERE WINE CODE BEGINS!! ** + **********************************************/ + DPRINT("Calling WINE code -- FileNameBuffer = '%S', Size = %lu, Buffer = 0x%p\n", FileNameBuffer, Size, Buffer); + return RtlpGetFullPath(FileNameBuffer, *PathType, Buffer, Size, SkipTrailingPathSeparators, ShortName); } NTSTATUS @@ -992,8 +1362,6 @@ return Length * sizeof(WCHAR); } - - /* * @implemented */ @@ -1199,284 +1567,6 @@ /****************************************************************** - * collapse_path - * - * Helper for RtlGetFullPathName_U. - * Get rid of . and .. components in the path. - */ -void FORCEINLINE collapse_path( WCHAR *path, UINT mark ) -{ - WCHAR *p, *next; - - /* convert every / into a \ */ - for (p = path; *p; p++) if (*p == '/') *p = '\\'; - - /* collapse duplicate backslashes */ - next = path + max( 1, mark ); - for (p = next; *p; p++) if (*p != '\\' || next[-1] != '\\') *next++ = *p; - *next = 0; - - p = path + mark; - while (*p) - { - if (*p == '.') - { - switch(p[1]) - { - case '\\': /* .\ component */ - next = p + 2; - memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); - continue; - case 0: /* final . */ - if (p > path + mark) p--; - *p = 0; - continue; - case '.': - if (p[2] == '\\') /* ..\ component */ - { - next = p + 3; - if (p > path + mark) - { - p--; - while (p > path + mark && p[-1] != '\\') p--; - } - memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); - continue; - } - else if (!p[2]) /* final .. */ - { - if (p > path + mark) - { - p--; - while (p > path + mark && p[-1] != '\\') p--; - if (p > path + mark) p--; - } - *p = 0; - continue; - } - break; - } - } - /* skip to the next component */ - while (*p && *p != '\\') p++; - if (*p == '\\') - { - /* remove last dot in previous dir name */ - if (p > path + mark && p[-1] == '.') memmove( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) ); - else p++; - } - } - - /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */ - while (p > path + mark && (p[-1] == ' ' || p[-1] == '.')) p--; - *p = 0; -} - - - -/****************************************************************** - * skip_unc_prefix - * - * Skip the \\share\dir\ part of a file name. Helper for RtlGetFullPathName_U. - */ -static const WCHAR *skip_unc_prefix( const WCHAR *ptr ) -{ - ptr += 2; - while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++; /* share name */ - while (IS_PATH_SEPARATOR(*ptr)) ptr++; - while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++; /* dir name */ - while (IS_PATH_SEPARATOR(*ptr)) ptr++; - return ptr; -} - - -/****************************************************************** - * 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) -{ - SIZE_T reqsize = 0, mark = 0, dep = 0, deplen; - LPWSTR ins_str = NULL; - LPCWSTR ptr; - const UNICODE_STRING* cd; - WCHAR tmp[4]; - - /* return error if name only consists of spaces */ - for (ptr = name; *ptr; ptr++) if (*ptr != ' ') break; - if (!*ptr) return 0; - - RtlAcquirePebLock(); - - //cd = &((PCURDIR)&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath)->DosPath; - cd = &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath; - - switch (RtlDetermineDosPathNameType_U(name)) - { - case RtlPathTypeUncAbsolute: /* \\foo */ - ptr = skip_unc_prefix( name ); - mark = (ptr - name); - break; - - case RtlPathTypeLocalDevice: /* \\.\foo */ - mark = 4; - break; - - case RtlPathTypeDriveAbsolute: /* c:\foo */ - reqsize = sizeof(WCHAR); - tmp[0] = towupper(name[0]); - ins_str = tmp; - dep = 1; - mark = 3; - break; - - case RtlPathTypeDriveRelative: /* c:foo */ - dep = 2; - if (towupper(name[0]) != towupper(cd->Buffer[0]) || cd->Buffer[1] != ':') - { - UNICODE_STRING var, val; - - 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 = (USHORT)size; - val.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, size); - if (val.Buffer == NULL) - { - reqsize = 0; - goto done; - } - - switch (RtlQueryEnvironmentVariable_U(NULL, &var, &val)) - { - case STATUS_SUCCESS: - /* FIXME: Win2k seems to check that the environment variable actually points - * to an existing directory. If not, root of the drive is used - * (this seems also to be the only spot in RtlGetFullPathName that the - * existence of a part of a path is checked) - */ - /* fall thru */ - case STATUS_BUFFER_TOO_SMALL: - 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); - tmp[0] = name[0]; - tmp[1] = ':'; - tmp[2] = '\\'; - ins_str = tmp; - RtlFreeHeap(RtlGetProcessHeap(), 0, val.Buffer); - break; - default: - DPRINT1("Unsupported status code\n"); - RtlFreeHeap(RtlGetProcessHeap(), 0, val.Buffer); - break; - } - mark = 3; - break; - } - /* fall through */ - - case RtlPathTypeRelative: /* foo */ - reqsize = cd->Length; - ins_str = cd->Buffer; - if (cd->Buffer[1] != ':') - { - ptr = skip_unc_prefix( cd->Buffer ); - mark = ptr - cd->Buffer; - } - else mark = 3; - break; - - case RtlPathTypeRooted: /* \xxx */ -#ifdef __WINE__ - if (name[0] == '/') /* may be a Unix path */ - { - const WCHAR *ptr = name; - int drive = find_drive_root( &ptr ); - if (drive != -1) - { - reqsize = 3 * sizeof(WCHAR); - tmp[0] = 'A' + drive; - tmp[1] = ':'; - tmp[2] = '\\'; - ins_str = tmp; - mark = 3; - dep = ptr - name; - break; - } - } -#endif - if (cd->Buffer[1] == ':') - { - reqsize = 2 * sizeof(WCHAR); - tmp[0] = cd->Buffer[0]; - tmp[1] = ':'; - ins_str = tmp; - mark = 3; - } - else - { - ptr = skip_unc_prefix( cd->Buffer ); - reqsize = (ptr - cd->Buffer) * sizeof(WCHAR); - mark = reqsize / sizeof(WCHAR); - ins_str = cd->Buffer; - } - break; - - case RtlPathTypeRootLocalDevice: /* \\. */ - reqsize = 4 * sizeof(WCHAR); - dep = 3; - tmp[0] = '\\'; - tmp[1] = '\\'; - tmp[2] = '.'; - tmp[3] = '\\'; - ins_str = tmp; - mark = 4; - break; - - case RtlPathTypeUnknown: - goto done; - } - - /* enough space ? */ - deplen = wcslen(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; - } - - memmove(buffer + reqsize / sizeof(WCHAR), name + dep, deplen + sizeof(WCHAR)); - if (reqsize) memcpy(buffer, ins_str, reqsize); - reqsize += deplen; - - if (ins_str && ins_str != tmp && ins_str != cd->Buffer) - RtlFreeHeap(RtlGetProcessHeap(), 0, ins_str); - - collapse_path( buffer, (ULONG)mark ); - reqsize = wcslen(buffer) * sizeof(WCHAR); - -done: - RtlReleasePebLock(); - return (ULONG)reqsize; -} - - -/****************************************************************** * RtlGetFullPathName_U (NTDLL.@) * * Returns the number of bytes written to buffer (not including the @@ -1488,60 +1578,33 @@ * * @implemented */ -ULONG NTAPI RtlGetFullPathName_U( - const WCHAR* name, - ULONG size, - WCHAR* buffer, - WCHAR** file_part) + +/* + * @implemented + */ +ULONG +NTAPI +RtlGetFullPathName_U( + _In_ PCWSTR FileName, + _In_ ULONG Size, + _Out_z_bytecap_(Size) PWSTR Buffer, + _Out_opt_ PWSTR *ShortName) { - WCHAR* ptr; - ULONG dosdev; - ULONG reqsize; + NTSTATUS Status; + UNICODE_STRING FileNameString; + RTL_PATH_TYPE PathType; - DPRINT("RtlGetFullPathName_U(%S %lu %p %p)\n", name, size, buffer, file_part); + /* Build the string */ + Status = RtlInitUnicodeStringEx(&FileNameString, FileName); + if (!NT_SUCCESS(Status)) return 0; - if (!name || !*name) return 0; - - /* Zero out the destination buffer (implies that "name" should be different from "buffer" to get this function well-behaving) */ - RtlZeroMemory(buffer, size); - - if (file_part) *file_part = NULL; - - /* check for DOS device name */ - dosdev = RtlIsDosDeviceName_U((WCHAR*)name); - if (dosdev) - { - DWORD offset = HIWORD(dosdev) / sizeof(WCHAR); /* get it in WCHARs, not bytes */ - DWORD sz = LOWORD(dosdev); /* in bytes */ - - if (8 + sz + 2 > size) return sz + 10; - wcscpy(buffer, DeviceRootW); - memmove(buffer + 4, name + offset, sz); - buffer[4 + sz / sizeof(WCHAR)] = '\0'; - /* file_part isn't set in this case */ - return sz + 8; - } - - reqsize = get_full_path_helper(name, buffer, size); - if (!reqsize) return 0; - if (reqsize > size) - { - LPWSTR tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, reqsize); - if (tmp == NULL) return 0; - reqsize = get_full_path_helper(name, tmp, reqsize); - if (reqsize + sizeof(WCHAR) > size) /* it may have worked the second time */ - { - RtlFreeHeap(RtlGetProcessHeap(), 0, tmp); - return reqsize + sizeof(WCHAR); - } - memcpy( buffer, tmp, reqsize + sizeof(WCHAR) ); - RtlFreeHeap(RtlGetProcessHeap(), 0, tmp); - } - - /* find file part */ - if (file_part && (ptr = wcsrchr(buffer, '\\')) != NULL && ptr >= buffer + 2 && *++ptr) - *file_part = ptr; - return reqsize; + /* Call the extended function */ + return RtlGetFullPathName_Ustr(&FileNameString, + Size, + Buffer, + (PCWSTR*)ShortName, + NULL, + &PathType); } /* @@ -1668,7 +1731,7 @@ while (*p) { /* Looking for an extension */ - if (*p == '.') + if (*p == L'.') { /* No extension string needed -- it's part of the filename */ Extension = NULL; @@ -1726,7 +1789,7 @@ if (*Path) { /* Loop as long as there's no semicolon */ - while (*Path != ';') + while (*Path != L';') { /* Copy the next character */ *BufferStart++ = *Path++; @@ -1734,7 +1797,7 @@ } /* We found a semi-colon, to stop path processing on this loop */ - if (*Path == ';') ++Path; + if (*Path == L';') ++Path; } /* Add a terminating slash if needed */ @@ -2449,7 +2512,7 @@ &StaticCandidateString, Status); } - DPRINT("STatus: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer); + DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer); } else { @@ -2472,7 +2535,7 @@ FileNameString, Status); } - DPRINT("STatus: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer); + DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer); } }