const UNICODE_STRING DeviceRootString = RTL_CONSTANT_STRING(L"\\\\.\\");
const UNICODE_STRING RtlpDosDevicesUncPrefix = RTL_CONSTANT_STRING(L"\\??\\UNC\\");
-const UNICODE_STRING RtlpWin32NtRootSlash = RTL_CONSTANT_STRING(L"\\\\?\\");
-const UNICODE_STRING RtlpDosSlashCONDevice = RTL_CONSTANT_STRING(L"\\\\.\\CON");
-const UNICODE_STRING RtlpDosDevicesPrefix = RTL_CONSTANT_STRING(L"\\??\\");
+const UNICODE_STRING RtlpWin32NtRootSlash = RTL_CONSTANT_STRING(L"\\\\?\\");
+const UNICODE_STRING RtlpDosSlashCONDevice = RTL_CONSTANT_STRING(L"\\\\.\\CON");
+const UNICODE_STRING RtlpDosDevicesPrefix = RTL_CONSTANT_STRING(L"\\??\\");
const UNICODE_STRING RtlpDosLPTDevice = RTL_CONSTANT_STRING(L"LPT");
const UNICODE_STRING RtlpDosCOMDevice = RTL_CONSTANT_STRING(L"COM");
/* PRIVATE FUNCTIONS **********************************************************/
+RTL_PATH_TYPE
+NTAPI
+RtlDetermineDosPathNameType_Ustr(IN PCUNICODE_STRING PathString)
+{
+ PWCHAR Path;
+ ULONG Chars;
+
+ Path = PathString->Buffer;
+ Chars = PathString->Length / sizeof(WCHAR);
+
+ /* Return if there are no characters */
+ if (!Chars) return RtlPathTypeRelative;
+
+ /*
+ * The algorithm is similar to RtlDetermineDosPathNameType_U but here we
+ * actually check for the path length before touching the characters
+ */
+ if (IS_PATH_SEPARATOR(Path[0]))
+ {
+ if ((Chars < 2) || !(IS_PATH_SEPARATOR(Path[1]))) return RtlPathTypeRooted; /* \x */
+ if ((Chars < 3) || ((Path[2] != L'.') && (Path[2] != L'?'))) return RtlPathTypeUncAbsolute;/* \\x */
+ if ((Chars >= 4) && (IS_PATH_SEPARATOR(Path[3]))) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */
+ if (Chars != 3) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */
+ return RtlPathTypeRootLocalDevice; /* \\. or \\? */
+ }
+ else
+ {
+ if ((Chars < 2) || (Path[1] != L':')) return RtlPathTypeRelative; /* x */
+ if ((Chars < 3) || !(IS_PATH_SEPARATOR(Path[2]))) return RtlPathTypeDriveRelative; /* x: */
+ return RtlPathTypeDriveAbsolute; /* x:\ */
+ }
+}
+
ULONG
NTAPI
RtlIsDosDeviceName_Ustr(IN PCUNICODE_STRING PathString)
{
/* 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);
{
/* Check if the character is a path or drive separator */
c = *End;
- if ((c == '\\') || (c == '/') || ((c == ':') && (End == PathCopy.Buffer + 1)))
+ if (IS_PATH_SEPARATOR(c) || ((c == L':') && (End == PathCopy.Buffer + 1)))
{
/* Get the next lower case character */
End++;
- c = *End | ' '; // ' ' == ('z' - 'Z')
+ c = RtlDowncaseUnicodeChar(*End);
/* 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);
}
/* Get the next lower case character and check if it's a DOS device */
- c = *PathCopy.Buffer | ' '; // ' ' == ('z' - 'Z')
- if ((c != 'l') && (c != 'c') && (c != 'p') && (c != 'a') && (c != 'n'))
+ c = RtlDowncaseUnicodeChar(*PathCopy.Buffer);
+ 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;
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);
/* 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);
return 0;
}
-RTL_PATH_TYPE
-NTAPI
-RtlDetermineDosPathNameType_Ustr(IN PCUNICODE_STRING PathString)
-{
- PWCHAR Path;
- ULONG Chars;
-
- /* Validate the input */
- if (!PathString) return RtlPathTypeUnknown;
-
- Path = PathString->Buffer;
- Chars = PathString->Length / sizeof(WCHAR);
-
- /* Return if there are no characters */
- if (!Chars) return RtlPathTypeUnknown;
-
- /*
- * The algorithm is similar to RtlDetermineDosPathNameType_U but here we
- * actually check for the path length before touching the characters
- */
- if ((Chars < 1) || (IS_PATH_SEPARATOR(Path[0])))
- {
- if ((Chars < 2) || !(IS_PATH_SEPARATOR(Path[1]))) return RtlPathTypeRooted; /* \x */
- if ((Chars < 3) || ((Path[2] != L'.') && (Path[2] != L'?'))) return RtlPathTypeUncAbsolute;/* \\x */
- if ((Chars >= 4) && (IS_PATH_SEPARATOR(Path[3]))) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */
- if (Chars != 3) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */
- return RtlPathTypeRootLocalDevice; /* \\. or \\? */
- }
- else
- {
- if ((Chars < 2) || (!(Path[0]) || (Path[1] != L':'))) return RtlPathTypeRelative; /* x */
- if ((Chars < 3) || (IS_PATH_SEPARATOR(Path[2]))) return RtlPathTypeDriveAbsolute; /* x:\ */
- return RtlPathTypeDriveRelative; /* x: */
- }
-}
-
NTSTATUS
NTAPI
RtlpCheckDeviceName(IN PUNICODE_STRING FileName,
return Status;
}
+
+
+/******************************************************************
+ * RtlpCollapsePath (from WINE)
+ *
+ * Helper for RtlGetFullPathName_U.
+ * 1) Convert slashes into backslashes
+ * 2) Get rid of duplicate backslashes
+ * 3) Get rid of . and .. components in the path.
+ */
+static VOID
+RtlpCollapsePath(PWSTR path, ULONG 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 = UNICODE_NULL;
+
+ p = path + mark;
+ while (*p)
+ {
+ if (*p == L'.')
+ {
+ switch(p[1])
+ {
+ case UNICODE_NULL: /* final . */
+ if (p > path + mark) p--;
+ *p = UNICODE_NULL;
+ continue;
+ case L'\\': /* .\ component */
+ next = p + 2;
+ RtlMoveMemory( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
+ 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 (after the UNC part if it exists) */
+ if (SkipTrailingPathSeparators)
+ {
+ while (p > path + mark && IS_PATH_SEPARATOR(p[-1])) *p-- = UNICODE_NULL;
+ }
+
+ /* Remove trailing spaces and dots (for all the path) */
+ while (p > path && (p[-1] == L' ' || p[-1] == L'.')) *p-- = UNICODE_NULL;
+
+ /* Null-terminate the string */
+ *p = UNICODE_NULL;
+}
+
+/******************************************************************
+ * RtlpSkipUNCPrefix (from WINE)
+ *
+ * Helper for RtlGetFullPathName_U
+ * Skip the \\share\dir part of a file name and return the new position
+ * (which can point on the last backslash of "dir\")
+ */
+static SIZE_T
+RtlpSkipUNCPrefix(PCWSTR FileNameBuffer)
+{
+ PCWSTR UncPath = FileNameBuffer + 2;
+ DPRINT("RtlpSkipUNCPrefix(%S)\n", FileNameBuffer);
+
+ while (*UncPath && !IS_PATH_SEPARATOR(*UncPath)) UncPath++; /* share name */
+ while (IS_PATH_SEPARATOR(*UncPath)) UncPath++;
+ while (*UncPath && !IS_PATH_SEPARATOR(*UncPath)) UncPath++; /* dir name */
+ /* while (IS_PATH_SEPARATOR(*UncPath)) UncPath++; */
+
+ return (UncPath - FileNameBuffer);
+}
+
+NTSTATUS
+NTAPI
+RtlpApplyLengthFunction(IN ULONG Flags,
+ IN ULONG Type,
+ IN PVOID UnicodeStringOrUnicodeStringBuffer,
+ IN PVOID LengthFunction)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RtlGetLengthWithoutLastFullDosOrNtPathElement(IN ULONG Flags,
+ IN PWCHAR Path,
+ OUT PULONG LengthOut)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RtlComputePrivatizedDllName_U(IN PUNICODE_STRING DllName,
+ IN PUNICODE_STRING a2,
+ IN PUNICODE_STRING a3)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
ULONG
NTAPI
-RtlGetFullPathName_Ustr(IN PUNICODE_STRING FileName,
- IN ULONG Size,
- IN PWSTR Buffer,
- OUT PCWSTR *ShortName,
- OUT PBOOLEAN InvalidName,
- OUT RTL_PATH_TYPE *PathType)
+RtlGetFullPathName_Ustr(
+ _In_ PUNICODE_STRING FileName,
+ _In_ ULONG Size,
+ _Out_z_bytecap_(Size) PWSTR Buffer,
+ _Out_opt_ PCWSTR *ShortName,
+ _Out_opt_ PBOOLEAN InvalidName,
+ _Out_ RTL_PATH_TYPE *PathType)
{
+ NTSTATUS Status;
PWCHAR FileNameBuffer;
ULONG FileNameLength, FileNameChars, DosLength, DosLengthOffset, FullLength;
+ BOOLEAN SkipTrailingPathSeparators;
WCHAR c;
- NTSTATUS Status;
+
+
+ ULONG reqsize = 0;
+ PCWSTR ptr;
+
+ PCUNICODE_STRING CurDirName;
+ UNICODE_STRING EnvVarName, EnvVarValue;
+ WCHAR EnvVarNameBuffer[4];
+
+ ULONG PrefixCut = 0; // Where the path really starts (after the skipped prefix)
+ PWCHAR Prefix = NULL; // pointer to the string to be inserted as the new path prefix
+ ULONG PrefixLength = 0;
+ PWCHAR Source;
+ ULONG SourceLength;
+
/* For now, assume the name is valid */
DPRINT("Filename: %wZ\n", FileName);
- DPRINT("Size and buffer: %lx %S\n", Size, Buffer);
+ DPRINT("Size and buffer: %lx %p\n", Size, Buffer);
if (InvalidName) *InvalidName = FALSE;
/* Handle initial path type and failure case */
*PathType = RtlPathTypeUnknown;
- if (!(Size) || !(Buffer) || !(FileName) ||
- !(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;
/* See comment for RtlIsDosDeviceName_Ustr if this is confusing... */
- DosLengthOffset = DosLength >> 16;
- DosLength = DosLength & 0xFFFF;
+ DosLengthOffset = HIWORD(DosLength);
+ DosLength = LOWORD(DosLength);
/* 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);
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 %lx and %S\n", FileNameBuffer, Size, Buffer);
- return RtlGetFullPathName_U(FileNameBuffer, Size, Buffer, (PWSTR*)ShortName);
+
+
+ /**********************************************
+ ** CODE REWRITTEN IS HAPPENING THERE **
+ **********************************************/
+ Source = FileNameBuffer;
+ SourceLength = FileNameLength;
+ EnvVarValue.Buffer = NULL;
+
+ /* Lock the PEB to get the current directory */
+ RtlAcquirePebLock();
+ CurDirName = &NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath;
+
+ switch (*PathType)
+ {
+ case RtlPathTypeUncAbsolute: /* \\foo */
+ PrefixCut = RtlpSkipUNCPrefix(FileNameBuffer);
+ break;
+
+ case RtlPathTypeLocalDevice: /* \\.\foo */
+ PrefixCut = 4;
+ break;
+
+ case RtlPathTypeDriveAbsolute: /* c:\foo */
+ ASSERT(FileNameBuffer[1] == L':');
+ ASSERT(IS_PATH_SEPARATOR(FileNameBuffer[2]));
+
+ Prefix = FileNameBuffer;
+ PrefixLength = 3 * sizeof(WCHAR);
+ Source += 3;
+ SourceLength -= 3 * sizeof(WCHAR);
+
+ PrefixCut = 3;
+ break;
+
+ case RtlPathTypeDriveRelative: /* c:foo */
+ Source += 2;
+ SourceLength -= 2 * sizeof(WCHAR);
+ if (RtlUpcaseUnicodeChar(FileNameBuffer[0]) != RtlUpcaseUnicodeChar(CurDirName->Buffer[0]) ||
+ CurDirName->Buffer[1] != L':')
+ {
+ EnvVarNameBuffer[0] = L'=';
+ EnvVarNameBuffer[1] = FileNameBuffer[0];
+ EnvVarNameBuffer[2] = L':';
+ EnvVarNameBuffer[3] = UNICODE_NULL;
+
+ EnvVarName.Length = 3 * sizeof(WCHAR);
+ EnvVarName.MaximumLength = EnvVarName.Length + sizeof(WCHAR);
+ EnvVarName.Buffer = EnvVarNameBuffer;
+
+ // FIXME: Is it possible to use the user-given buffer ?
+ // RtlInitEmptyUnicodeString(&EnvVarValue, NULL, Size);
+ EnvVarValue.Length = 0;
+ EnvVarValue.MaximumLength = (USHORT)Size;
+ EnvVarValue.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
+ if (EnvVarValue.Buffer == NULL)
+ {
+ Prefix = NULL;
+ PrefixLength = 0;
+ goto Quit;
+ }
+
+ Status = RtlQueryEnvironmentVariable_U(NULL, &EnvVarName, &EnvVarValue);
+ switch (Status)
+ {
+ 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).
+ */
+ EnvVarValue.Buffer[EnvVarValue.Length / sizeof(WCHAR)] = L'\\';
+ Prefix = EnvVarValue.Buffer;
+ PrefixLength = EnvVarValue.Length + sizeof(WCHAR); /* Append trailing '\\' */
+ break;
+
+ case STATUS_BUFFER_TOO_SMALL:
+ reqsize = EnvVarValue.Length + SourceLength + sizeof(UNICODE_NULL);
+ goto Quit;
+
+ default:
+ DPRINT1("RtlQueryEnvironmentVariable_U returned 0x%08lx\n", Status);
+
+ EnvVarNameBuffer[0] = FileNameBuffer[0];
+ EnvVarNameBuffer[1] = L':';
+ EnvVarNameBuffer[2] = L'\\';
+ EnvVarNameBuffer[3] = UNICODE_NULL;
+ Prefix = EnvVarNameBuffer;
+ PrefixLength = 3 * sizeof(WCHAR);
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, EnvVarValue.Buffer);
+ EnvVarValue.Buffer = NULL;
+ break;
+ }
+ PrefixCut = 3;
+ break;
+ }
+ /* Fall through */
+ DPRINT("RtlPathTypeDriveRelative - Using fall-through to RtlPathTypeRelative\n");
+
+ case RtlPathTypeRelative: /* foo */
+ Prefix = CurDirName->Buffer;
+ PrefixLength = CurDirName->Length;
+ if (CurDirName->Buffer[1] != L':')
+ {
+ PrefixCut = RtlpSkipUNCPrefix(CurDirName->Buffer);
+ }
+ else
+ {
+ PrefixCut = 3;
+ }
+ break;
+
+ case RtlPathTypeRooted: /* \xxx */
+ if (CurDirName->Buffer[1] == L':')
+ {
+ // The path starts with "C:\"
+ ASSERT(CurDirName->Buffer[1] == L':');
+ ASSERT(IS_PATH_SEPARATOR(CurDirName->Buffer[2]));
+
+ Prefix = CurDirName->Buffer;
+ PrefixLength = 3 * sizeof(WCHAR); // Skip "C:\"
+
+ PrefixCut = 3; // Source index location incremented of + 3
+ }
+ else
+ {
+ PrefixCut = RtlpSkipUNCPrefix(CurDirName->Buffer);
+ PrefixLength = PrefixCut * sizeof(WCHAR);
+ Prefix = CurDirName->Buffer;
+ }
+ break;
+
+ case RtlPathTypeRootLocalDevice: /* \\. */
+ Prefix = DeviceRootString.Buffer;
+ PrefixLength = DeviceRootString.Length;
+ Source += 3;
+ SourceLength -= 3 * sizeof(WCHAR);
+
+ PrefixCut = 4;
+ break;
+
+ case RtlPathTypeUnknown:
+ goto Quit;
+ }
+
+ /* Do we have enough space for storing the full path? */
+ reqsize = PrefixLength;
+ if (reqsize + SourceLength + sizeof(WCHAR) > Size)
+ {
+ /* Not enough space, return needed size (including terminating '\0') */
+ reqsize += SourceLength + sizeof(WCHAR);
+ goto Quit;
+ }
+
+ /*
+ * Build the full path
+ */
+ // if (ShortName) DPRINT1("buffer(1) = %S\n", Buffer);
+ /* Copy the path's prefix */
+ if (PrefixLength) RtlMoveMemory(Buffer, Prefix, PrefixLength);
+ // if (ShortName) DPRINT1("buffer(2) = %S\n", Buffer);
+ /* Copy the remaining part of the path */
+ RtlMoveMemory(Buffer + PrefixLength / sizeof(WCHAR), Source, SourceLength + sizeof(WCHAR));
+ // if (ShortName) DPRINT1("buffer(3) = %S\n", Buffer);
+
+ /* Some cleanup */
+ Prefix = NULL;
+ if (EnvVarValue.Buffer)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, EnvVarValue.Buffer);
+ EnvVarValue.Buffer = NULL;
+ }
+
+ /*
+ * Finally, put the path in canonical form,
+ * i.e. simplify redundant . and .., etc...
+ */
+ // if (*PathType == RtlPathTypeUncAbsolute) DPRINT1("RtlpCollapsePath('%S', %lu)\n", Buffer, PrefixCut);
+ RtlpCollapsePath(Buffer, PrefixCut, 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.
+ */
+ PrefixCut = (*PathType == RtlPathTypeUncAbsolute ? PrefixCut : 3);
+
+ if (ptr && *ptr && (ptr >= Buffer + PrefixCut))
+ {
+ *ShortName = ptr;
+ }
+ else
+ {
+ /* Zero-out the short name */
+ *ShortName = NULL;
+ }
+ }
+
+Quit:
+ /* Release PEB lock */
+ RtlReleasePebLock();
+ return (ULONG)reqsize;
}
NTSTATUS
if (PartName)
{
/* Loop from the back until we find a path separator */
- p = &NewBuffer[(DosLength - 1) / sizeof (WCHAR)];
- while (p > NewBuffer) if (*p-- == '\\') break;
-
- /* Was one found? */
- if (p > NewBuffer)
+ p = &NewBuffer[DosLength / sizeof(WCHAR)];
+ while (--p > NewBuffer)
{
- /* Move past it -- anything left? */
- p++;
- if (!*p)
- {
- /* The path ends with a path separator, no part name */
- *PartName = NULL;
- }
- else
+ /* We found a path separator, move past it */
+ if (*p == OBJ_NAME_PATH_SEPARATOR)
{
- /* What follows the path separator is the part name */
- *PartName = p;
+ ++p;
+ break;
}
}
+
+ /* Check whether a separator was found and if something remains */
+ if ((p > NewBuffer) && *p)
+ {
+ /* What follows the path separator is the partial name */
+ *PartName = p;
+ }
+ else
+ {
+ /* The path ends with a path separator, no partial name */
+ *PartName = NULL;
+ }
}
/* Build the final NT path string */
- NtPath->Length = (USHORT)DosLength;
NtPath->Buffer = NewBuffer;
+ NtPath->Length = (USHORT)DosLength;
NtPath->MaximumLength = (USHORT)DosLength + sizeof(UNICODE_NULL);
return STATUS_SUCCESS;
}
PCURDIR CurrentDirectory;
/* Assume MAX_PATH for now */
- DPRINT("Relative: %lx DosName: %wZ NtName: %wZ, PartName: %p, RelativeName: %p\n",
+ DPRINT("Relative: %lx DosName: %wZ NtName: %p, PartName: %p, RelativeName: %p\n",
HaveRelative, DosName, NtName, PartName, RelativeName);
MaxLength = sizeof(BigBuffer);
/* Capture input string */
CapturedDosName = *DosName;
- /* Check for \\?\\ form */
+ /* Check for the presence or absence of the NT prefix "\\?\" form */
+ // if (!RtlPrefixUnicodeString(&RtlpWin32NtRootSlash, &CapturedDosName, FALSE))
if ((CapturedDosName.Length <= RtlpWin32NtRootSlash.Length) ||
(CapturedDosName.Buffer[0] != RtlpWin32NtRootSlash.Buffer[0]) ||
(CapturedDosName.Buffer[1] != RtlpWin32NtRootSlash.Buffer[1]) ||
(CapturedDosName.Buffer[2] != RtlpWin32NtRootSlash.Buffer[2]) ||
(CapturedDosName.Buffer[3] != RtlpWin32NtRootSlash.Buffer[3]))
{
+ /* NT prefix not present */
+
/* Quick path won't be used */
QuickPath = FALSE;
/* Allocate a buffer to hold the path */
NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, MaxLength);
- DPRINT("Length: %lx\n", MaxLength);
+ DPRINT("MaxLength: %lx\n", MaxLength);
if (!NewBuffer) return STATUS_NO_MEMORY;
}
else
{
+ /* NT prefix present */
+
/* Use the optimized path after acquiring the lock */
QuickPath = TRUE;
NewBuffer = NULL;
/* Nothing else is expected */
default:
ASSERT(FALSE);
-
}
/* Now copy the prefix and the buffer */
RtlCopyMemory(NewBuffer, PrefixBuffer, PrefixLength);
RtlCopyMemory((PCHAR)NewBuffer + PrefixLength,
- &Buffer[PrefixCut],
+ Buffer + PrefixCut,
PathLength - (PrefixCut * sizeof(WCHAR)));
/* Compute the length */
- Length = PathLength - PrefixCut * sizeof(WCHAR) + PrefixLength;
+ Length = PathLength + PrefixLength - PrefixCut * sizeof(WCHAR);
LengthChars = Length / sizeof(WCHAR);
/* Setup the actual NT path string and terminate it */
NtName->Length = (USHORT)Length;
NtName->MaximumLength = (USHORT)MaxLength;
NewBuffer[LengthChars] = UNICODE_NULL;
- DPRINT("new buffer: %S\n", NewBuffer);
+ DPRINT("New buffer: %S\n", NewBuffer);
DPRINT("NT Name: %wZ\n", NtName);
/* Check if a partial name was requested */
if (RtlEqualUnicodeString(&FullPath, &CurrentDirectory->DosPath, TRUE))
{
/* Make relative name string */
- RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)NewBuffer + FullPath.Length - PrefixCut);
+ RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)NewBuffer + PrefixLength + FullPath.Length - PrefixCut * sizeof(WCHAR));
RelativeName->RelativeName.Length = (USHORT)(PathLength - FullPath.Length);
/* If relative name starts with \, skip it */
- if (RelativeName->RelativeName.Buffer[0] == L'\\')
+ if (RelativeName->RelativeName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
{
- RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)RelativeName->RelativeName.Buffer + sizeof(WCHAR));
+ RelativeName->RelativeName.Buffer++;
RelativeName->RelativeName.Length -= sizeof(WCHAR);
}
RelativeName->RelativeName.MaximumLength = RelativeName->RelativeName.Length;
NTSTATUS Status;
FILE_BASIC_INFORMATION BasicInformation;
- /* Validate the input */
- if (!FileName) return FALSE;
-
/* Get the NT Path */
Result = RtlDosPathNameToRelativeNtPathName_Ustr(FileName,
&NtPathName,
* This is, and has always been equal to, 269 characters, except in Wine
* which claims this is 277. Go figure.
*/
- return (MAX_PATH + RtlpDosDevicesUncPrefix.Length + sizeof(ANSI_NULL));
+ return MAX_PATH + RtlpDosDevicesUncPrefix.Length / sizeof(WCHAR) + sizeof(ANSI_NULL);
}
/*
* @implemented
+ * @note: the export is called RtlGetLengthWithoutTrailingPathSeperators
+ * (with a 'e' instead of a 'a' in "Seperators").
*/
-ULONG
+NTSTATUS
+NTAPI
+RtlGetLengthWithoutTrailingPathSeparators(IN ULONG Flags,
+ IN PCUNICODE_STRING PathString,
+ OUT PULONG Length)
+{
+ ULONG NumChars;
+
+ /* Parameters validation */
+ if (Length == NULL) return STATUS_INVALID_PARAMETER;
+
+ *Length = 0;
+
+ if (PathString == NULL) return STATUS_INVALID_PARAMETER;
+
+ /* No flags are supported yet */
+ if (Flags != 0) return STATUS_INVALID_PARAMETER;
+
+ NumChars = PathString->Length / sizeof(WCHAR);
+
+ /*
+ * Notice that we skip the last character, therefore:
+ * - if we have: "some/path/f" we test for: "some/path/"
+ * - if we have: "some/path/" we test for: "some/path"
+ * - if we have: "s" we test for: ""
+ * - if we have: "" then NumChars was already zero and we aren't there
+ */
+
+ while (NumChars > 0 && IS_PATH_SEPARATOR(PathString->Buffer[NumChars - 1]))
+ {
+ --NumChars;
+ }
+
+ *Length = NumChars;
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+RTL_PATH_TYPE
NTAPI
RtlDetermineDosPathNameType_U(IN PCWSTR Path)
{
DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
- /* Validate the input */
- if (!Path) return RtlPathTypeUnknown;
-
/* Unlike the newer RtlDetermineDosPathNameType_U we assume 4 characters */
if (IS_PATH_SEPARATOR(Path[0]))
{
*/
ULONG
NTAPI
-RtlGetCurrentDirectory_U(IN ULONG MaximumLength,
- IN PWSTR Buffer)
+RtlGetCurrentDirectory_U(
+ _In_ ULONG MaximumLength,
+ _Out_bytecap_(MaximumLength) PWSTR Buffer)
{
ULONG Length, Bytes;
PCURDIR CurDir;
OBJECT_ATTRIBUTES ObjectAttributes;
FILE_FS_DEVICE_INFORMATION FileFsDeviceInfo;
ULONG SavedLength, CharLength, FullPathLength;
- HANDLE OldHandle = 0, CurDirHandle, OldCurDirHandle = 0;
+ HANDLE OldHandle = NULL, CurDirHandle = NULL, OldCurDirHandle = NULL;
DPRINT("RtlSetCurrentDirectory_U %wZ\n", Path);
+ /* Initialize for failure case */
+ RtlInitEmptyUnicodeString(&NtName, NULL, 0);
+
/* Can't set current directory on DOS device */
if (RtlIsDosDeviceName_Ustr(Path))
{
{
/* Get back normal handle */
CurDirHandle = (HANDLE)((ULONG_PTR)(CurDir->Handle) & ~RTL_CURDIR_ALL_FLAGS);
- CurDir->Handle = 0;
+ CurDir->Handle = NULL;
/* Get device information */
Status = NtQueryVolumeInformationFile(CurDirHandle,
FullPath.Length = (USHORT)FullPathLength;
/* If full path isn't \ terminated, do it */
- if (FullPath.Buffer[CharLength - 1] != L'\\')
+ if (FullPath.Buffer[CharLength - 1] != OBJ_NAME_PATH_SEPARATOR)
{
if ((CharLength + 1) * sizeof(WCHAR) > SavedLength)
{
goto Leave;
}
- FullPath.Buffer[CharLength] = L'\\';
+ FullPath.Buffer[CharLength] = OBJ_NAME_PATH_SEPARATOR;
FullPath.Buffer[CharLength + 1] = UNICODE_NULL;
FullPath.Length += sizeof(WCHAR);
}
/* Save new data */
CurDir->Handle = CurDirHandle;
RtlpCurDirRef->Handle = CurDirHandle;
- CurDirHandle = 0;
+ CurDirHandle = NULL;
/* Copy full path */
RtlCopyMemory(CurDir->DosPath.Buffer, FullPath.Buffer, FullPath.Length + sizeof(WCHAR));
}
-/******************************************************************
- * 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 != 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.@)
*
*
* @implemented
*/
-ULONG NTAPI RtlGetFullPathName_U(
- const WCHAR* name,
- ULONG size,
- WCHAR* buffer,
- WCHAR** file_part)
-{
- WCHAR* ptr;
- ULONG dosdev;
- ULONG reqsize;
- DPRINT("RtlGetFullPathName_U(%S %lu %p %p)\n", name, size, buffer, file_part);
-
- if (!name || !*name) return 0;
-
- 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;
- }
+/*
+ * @implemented
+ */
+ULONG
+NTAPI
+RtlGetFullPathName_U(
+ _In_ PCWSTR FileName,
+ _In_ ULONG Size,
+ _Out_z_bytecap_(Size) PWSTR Buffer,
+ _Out_opt_ PWSTR *ShortName)
+{
+ NTSTATUS Status;
+ UNICODE_STRING FileNameString;
+ RTL_PATH_TYPE PathType;
- 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);
- }
+ /* Build the string */
+ Status = RtlInitUnicodeStringEx(&FileNameString, FileName);
+ if (!NT_SUCCESS(Status)) return 0;
- /* 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);
}
/*
PWCHAR NewBuffer, BufferStart;
PCWSTR p;
- /* Validate the input */
- if (!(Path) || !(FileName)) return 0;
-
/* Check if this is an absolute path */
if (RtlDetermineDosPathNameType_U(FileName) != RtlPathTypeRelative)
{
while (*p)
{
/* Looking for an extension */
- if (*p == '.')
+ if (*p == L'.')
{
/* No extension string needed -- it's part of the filename */
Extension = NULL;
if (*Path)
{
/* Loop as long as there's no semicolon */
- while (*Path != ';')
+ while (*Path != L';')
{
/* Copy the next character */
*BufferStart++ = *Path++;
}
/* 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 */
- if ((BufferStart != NewBuffer) && (BufferStart[-1] != '\\'))
+ if ((BufferStart != NewBuffer) && (BufferStart[-1] != OBJ_NAME_PATH_SEPARATOR))
{
- *BufferStart++ = '\\';
+ *BufferStart++ = OBJ_NAME_PATH_SEPARATOR;
}
/* Bail out if we reached the end */
/*
* @implemented
*/
-ULONG
+NTSTATUS
NTAPI
RtlGetFullPathName_UstrEx(IN PUNICODE_STRING FileName,
IN PUNICODE_STRING StaticString,
&ShortName,
NameInvalid,
PathType);
- DPRINT("Length: %d StaticBuffer: %S\n", Length, StaticBuffer);
+ DPRINT("Length: %u StaticBuffer: %S\n", Length, StaticBuffer);
if (!Length)
{
/* Fail if it failed */
Quickie:
/* Free any buffers we should be freeing */
DPRINT("Status: %lx %S %S\n", Status, StaticBuffer, TempDynamicString.Buffer);
- if ((StaticBuffer) && (StaticBuffer != StaticString->Buffer))
+ if ((StaticString) && (StaticBuffer) && (StaticBuffer != StaticString->Buffer))
{
RtlpFreeMemory(StaticBuffer, TAG_USTR);
}
/*
* @implemented
*/
-ULONG
+NTSTATUS
NTAPI
RtlDosSearchPath_Ustr(IN ULONG Flags,
IN PUNICODE_STRING PathString,
sizeof(StaticCandidateBuffer));
/* Initialize optional arguments */
- if (FullNameOut) *FullNameOut = NULL;
+ if (FullNameOut ) *FullNameOut = NULL;
if (FilePartSize) *FilePartSize = 0;
+ if (LengthNeeded) *LengthNeeded = 0;
if (DynamicString)
{
DynamicString->Length = DynamicString->MaximumLength = 0;
"the search path, but RtlGetfullPathNameUStrEx() "
"returned %08lx\n",
__FUNCTION__,
+ &StaticCandidateString,
Status);
}
- DPRINT("STatus: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
+ DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
goto Quickie;
}
else
}
/* Copy the filename */
- RtlCopyMemory(StaticCandidateString.Buffer,
- FileNameString->Buffer,
- FileNameString->Length);
+ RtlCopyUnicodeString(&StaticCandidateString, FileNameString);
/* Copy the extension */
- RtlCopyMemory(&StaticCandidateString.Buffer[FileNameString->Length / sizeof(WCHAR)],
- ExtensionString->Buffer,
- ExtensionString->Length);
-
- /* Now NULL-terminate */
- StaticCandidateString.Buffer[StaticCandidateString.Length / sizeof(WCHAR)] = UNICODE_NULL;
+ RtlAppendUnicodeStringToString(&StaticCandidateString,
+ ExtensionString);
- /* Finalize the length of the string to make it valid */
- StaticCandidateString.Length = FileNameString->Length + ExtensionString->Length;
DPRINT("SB: %wZ\n", &StaticCandidateString);
/* And check if this file now exists */
&StaticCandidateString,
Status);
}
- DPRINT("STatus: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
+ DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
}
else
{
FileNameString,
Status);
}
- DPRINT("STatus: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
+ DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
}
}