ReactOS 0.4.15-dev-7918-g2a2556c
path.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/rtl/path.c
5 * PURPOSE: Path and current directory functions
6 * PROGRAMMERS: Wine team
7 * Thomas Weidenmueller
8 * Gunnar Dalsnes
9 * Alex Ionescu (alex.ionescu@reactos.org)
10 * Pierre Schweitzer (pierre@reactos.org)
11 */
12
13/* INCLUDES *******************************************************************/
14
15#include <rtl.h>
16
17#define NDEBUG
18#include <debug.h>
19
20/* DEFINITONS and MACROS ******************************************************/
21
22#define MAX_PFX_SIZE 16
23
24#define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/'))
25
26#define RTL_CURDIR_IS_REMOVABLE 0x1
27#define RTL_CURDIR_DROP_OLD_HANDLE 0x2
28#define RTL_CURDIR_ALL_FLAGS (RTL_CURDIR_DROP_OLD_HANDLE | RTL_CURDIR_IS_REMOVABLE) // 0x3
30
31
32/* GLOBALS ********************************************************************/
33
35
40
47
49
53
54
56
57/* PRIVATE FUNCTIONS **********************************************************/
58
62{
64 ULONG Chars;
65
66 Path = PathString->Buffer;
67 Chars = PathString->Length / sizeof(WCHAR);
68
69 /* Return if there are no characters */
70 if (!Chars) return RtlPathTypeRelative;
71
72 /*
73 * The algorithm is similar to RtlDetermineDosPathNameType_U but here we
74 * actually check for the path length before touching the characters
75 */
76 if (IS_PATH_SEPARATOR(Path[0]))
77 {
78 if ((Chars < 2) || !(IS_PATH_SEPARATOR(Path[1]))) return RtlPathTypeRooted; /* \x */
79 if ((Chars < 3) || ((Path[2] != L'.') && (Path[2] != L'?'))) return RtlPathTypeUncAbsolute;/* \\x */
80 if ((Chars >= 4) && (IS_PATH_SEPARATOR(Path[3]))) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */
81 if (Chars != 3) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */
82 return RtlPathTypeRootLocalDevice; /* \\. or \\? */
83 }
84 else
85 {
86 if ((Chars < 2) || (Path[1] != L':')) return RtlPathTypeRelative; /* x */
87 if ((Chars < 3) || !(IS_PATH_SEPARATOR(Path[2]))) return RtlPathTypeDriveRelative; /* x: */
88 return RtlPathTypeDriveAbsolute; /* x:\ */
89 }
90}
91
95{
96 UNICODE_STRING PathCopy;
97 PWCHAR Start, End;
98 USHORT PathChars, ColonCount = 0;
99 USHORT ReturnOffset = 0, ReturnLength, OriginalLength;
100 WCHAR c;
101
102 /* Validate the input */
103 if (!PathString) return 0;
104
105 /* Check what type of path this is */
106 switch (RtlDetermineDosPathNameType_Ustr(PathString))
107 {
108 /* Fail for UNC or unknown paths */
111 return 0;
112
113 /* Make special check for the CON device */
116 {
117 /* This should return 0x80006 */
119 }
120 return 0;
121
122 default:
123 break;
124 }
125
126 /* Make a copy of the string */
127 PathCopy = *PathString;
128 OriginalLength = PathString->Length;
129
130 /* Return if there's no characters */
131 PathChars = PathCopy.Length / sizeof(WCHAR);
132 if (!PathChars) return 0;
133
134 /* Check for drive path and truncate */
135 if (PathCopy.Buffer[PathChars - 1] == L':')
136 {
137 /* Fixup the lengths */
138 PathCopy.Length -= sizeof(WCHAR);
139 if (!--PathChars) return 0;
140
141 /* Remember this for later */
142 ColonCount = 1;
143 }
144
145 /* Check for extension or space, and truncate */
146 do
147 {
148 /* Stop if we hit something else than a space or period */
149 c = PathCopy.Buffer[PathChars - 1];
150 if ((c != L'.') && (c != L' ')) break;
151
152 /* Fixup the lengths */
153 PathCopy.Length -= sizeof(WCHAR);
154
155 /* Remember this for later */
156 ColonCount++;
157 } while (--PathChars);
158
159 /* Anything still left? */
160 if (PathChars)
161 {
162 /* Loop from the end */
163 for (End = &PathCopy.Buffer[PathChars - 1];
164 End >= PathCopy.Buffer;
165 --End)
166 {
167 /* Check if the character is a path or drive separator */
168 c = *End;
169 if (IS_PATH_SEPARATOR(c) || ((c == L':') && (End == PathCopy.Buffer + 1)))
170 {
171 /* Get the next lower case character */
172 End++;
174
175 /* Check if it's a DOS device (LPT, COM, PRN, AUX, or NUL) */
176 if ((End < &PathCopy.Buffer[OriginalLength / sizeof(WCHAR)]) &&
177 ((c == L'l') || (c == L'c') || (c == L'p') || (c == L'a') || (c == L'n')))
178 {
179 /* Calculate the offset */
180 ReturnOffset = (USHORT)((PCHAR)End - (PCHAR)PathCopy.Buffer);
181
182 /* Build the final string */
183 PathCopy.Length = OriginalLength - ReturnOffset - (ColonCount * sizeof(WCHAR));
184 PathCopy.Buffer = End;
185
186 /* Save new amount of chars in the path */
187 PathChars = PathCopy.Length / sizeof(WCHAR);
188
189 break;
190 }
191 else
192 {
193 return 0;
194 }
195 }
196 }
197
198 /* Get the next lower case character and check if it's a DOS device */
199 c = RtlpDowncaseUnicodeChar(*PathCopy.Buffer);
200 if ((c != L'l') && (c != L'c') && (c != L'p') && (c != L'a') && (c != L'n'))
201 {
202 /* Not LPT, COM, PRN, AUX, or NUL */
203 return 0;
204 }
205 }
206
207 /* Now skip past any extra extension or drive letter characters */
208 Start = PathCopy.Buffer;
209 End = &Start[PathChars];
210 while (Start < End)
211 {
212 c = *Start;
213 if ((c == L'.') || (c == L':')) break;
214 Start++;
215 }
216
217 /* And then go backwards to get rid of spaces */
218 while ((Start > PathCopy.Buffer) && (Start[-1] == L' ')) --Start;
219
220 /* Finally see how many characters are left, and that's our size */
221 PathChars = (USHORT)(Start - PathCopy.Buffer);
222 PathCopy.Length = PathChars * sizeof(WCHAR);
223
224 /* Check if this is a COM or LPT port, which has a digit after it */
225 if ((PathChars == 4) &&
226 (iswdigit(PathCopy.Buffer[3]) && (PathCopy.Buffer[3] != L'0')))
227 {
228 /* Don't compare the number part, just check for LPT or COM */
229 PathCopy.Length -= sizeof(WCHAR);
230 if ((RtlEqualUnicodeString(&PathCopy, &RtlpDosLPTDevice, TRUE)) ||
232 {
233 /* Found it */
234 ReturnLength = sizeof(L"COM1") - sizeof(WCHAR);
235 return MAKELONG(ReturnLength, ReturnOffset);
236 }
237 }
238 else if ((PathChars == 3) &&
243 {
244 /* Otherwise this was something like AUX, NUL, PRN, or CON */
245 ReturnLength = sizeof(L"AUX") - sizeof(WCHAR);
246 return MAKELONG(ReturnLength, ReturnOffset);
247 }
248
249 /* Otherwise, this is not a valid DOS device */
250 return 0;
251}
252
254NTAPI
258{
261
262 /* Allocate a large enough buffer */
263 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, FileName->Length);
264 if (Buffer)
265 {
266 /* Assume failure */
267 *NameInvalid = TRUE;
268
269 /* Copy the filename */
270 RtlCopyMemory(Buffer, FileName->Buffer, FileName->Length);
271
272 /* And add a dot at the end */
273 Buffer[Length / sizeof(WCHAR)] = L'.';
274 Buffer[(Length / sizeof(WCHAR)) + 1] = UNICODE_NULL;
275
276 /* Check if the file exists or not */
278
279 /* Get rid of the buffer now */
280 Status = RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
281 }
282 else
283 {
284 /* Assume the name is ok, but fail the call */
287 }
288
289 /* Return the status */
290 return Status;
291}
292
293
294
295/******************************************************************
296 * RtlpCollapsePath (from WINE)
297 *
298 * Helper for RtlGetFullPathName_U
299 *
300 * 1) Converts slashes into backslashes and gets rid of duplicated ones;
301 * 2) Gets rid of . and .. components in the path.
302 *
303 * Returns the full path length without its terminating NULL character.
304 */
305static ULONG
306RtlpCollapsePath(PWSTR Path, /* ULONG PathBufferSize, ULONG PathLength, */ ULONG mark, BOOLEAN SkipTrailingPathSeparators)
307{
308 PWSTR p, next;
309
310 // FIXME: Do not suppose NULL-terminated strings!!
311
313 PWSTR EndBuffer = Path + PathLength; // Path + PathBufferSize / sizeof(WCHAR);
315
316 /* Convert slashes into backslashes */
317 for (p = Path; *p; p++)
318 {
319 if (*p == L'/') *p = L'\\';
320 }
321
322 /* Collapse duplicate backslashes */
323 next = Path + max( 1, mark );
324 for (p = next; *p; p++)
325 {
326 if (*p != L'\\' || next[-1] != L'\\') *next++ = *p;
327 }
329 EndPath = next;
330
331 p = Path + mark;
332 while (*p)
333 {
334 if (*p == L'.')
335 {
336 switch (p[1])
337 {
338 case UNICODE_NULL: /* final . */
339 if (p > Path + mark) p--;
340 *p = UNICODE_NULL;
341 EndPath = p;
342 continue;
343
344 case L'\\': /* .\ component */
345 next = p + 2;
346 // ASSERT(EndPath - next == wcslen(next));
347 RtlMoveMemory(p, next, (EndPath - next + 1) * sizeof(WCHAR));
348 EndPath -= (next - p);
349 continue;
350
351 case L'.':
352 if (p[2] == L'\\') /* ..\ component */
353 {
354 next = p + 3;
355 if (p > Path + mark)
356 {
357 p--;
358 while (p > Path + mark && p[-1] != L'\\') p--;
359 }
360 // ASSERT(EndPath - next == wcslen(next));
361 RtlMoveMemory(p, next, (EndPath - next + 1) * sizeof(WCHAR));
362 EndPath -= (next - p);
363 continue;
364 }
365 else if (p[2] == UNICODE_NULL) /* final .. */
366 {
367 if (p > Path + mark)
368 {
369 p--;
370 while (p > Path + mark && p[-1] != L'\\') p--;
371 if (p > Path + mark) p--;
372 }
373 *p = UNICODE_NULL;
374 EndPath = p;
375 continue;
376 }
377 break;
378 }
379 }
380
381 /* Skip to the next component */
382 while (*p && *p != L'\\') p++;
383 if (*p == L'\\')
384 {
385 /* Remove last dot in previous dir name */
386 if (p > Path + mark && p[-1] == L'.')
387 {
388 // ASSERT(EndPath - p == wcslen(p));
389 RtlMoveMemory(p - 1, p, (EndPath - p + 1) * sizeof(WCHAR));
390 EndPath--;
391 }
392 else
393 {
394 p++;
395 }
396 }
397 }
398
399 /* Remove trailing backslashes if needed (after the UNC part if it exists) */
400 if (SkipTrailingPathSeparators)
401 {
402 while (p > Path + mark && IS_PATH_SEPARATOR(p[-1])) p--;
403 }
404
405 /* Remove trailing spaces and dots (for all the path) */
406 while (p > Path && (p[-1] == L' ' || p[-1] == L'.')) p--;
407
408 /*
409 * Zero-out the discarded buffer zone, starting just after
410 * the path string and going up to the end of the buffer.
411 * It also NULL-terminate the path string.
412 */
413 ASSERT(EndBuffer >= p);
414 RtlZeroMemory(p, (EndBuffer - p + 1) * sizeof(WCHAR));
415
416 /* Return the real path length */
417 PathLength = (p - Path);
418 // ASSERT(PathLength == wcslen(Path));
419 return (PathLength * sizeof(WCHAR));
420}
421
422/******************************************************************
423 * RtlpSkipUNCPrefix (from WINE)
424 *
425 * Helper for RtlGetFullPathName_U
426 *
427 * Skips the \\share\dir part of a file name and returns the new position
428 * (which can point on the last backslash of "dir\").
429 */
430static SIZE_T
432{
433 PCWSTR UncPath = FileNameBuffer + 2;
434 DPRINT("RtlpSkipUNCPrefix(%S)\n", FileNameBuffer);
435
436 while (*UncPath && !IS_PATH_SEPARATOR(*UncPath)) UncPath++; /* share name */
437 while (IS_PATH_SEPARATOR(*UncPath)) UncPath++;
438 while (*UncPath && !IS_PATH_SEPARATOR(*UncPath)) UncPath++; /* dir name */
439 /* while (IS_PATH_SEPARATOR(*UncPath)) UncPath++; */
440
441 return (UncPath - FileNameBuffer);
442}
443
445NTAPI
447 IN ULONG Type,
448 IN PVOID UnicodeStringOrUnicodeStringBuffer,
449 IN NTSTATUS(NTAPI* LengthFunction)(ULONG, PUNICODE_STRING, PULONG))
450{
454
455 if (Flags || UnicodeStringOrUnicodeStringBuffer == NULL || LengthFunction == NULL)
456 {
457 DPRINT1("ERROR: Flags=0x%x, UnicodeStringOrUnicodeStringBuffer=%p, LengthFunction=%p\n",
458 Flags, UnicodeStringOrUnicodeStringBuffer, LengthFunction);
460 }
461
462 if (Type == sizeof(UNICODE_STRING))
463 {
464 String = (PUNICODE_STRING)UnicodeStringOrUnicodeStringBuffer;
465 }
466 else if (Type == sizeof(RTL_UNICODE_STRING_BUFFER))
467 {
468 String = &((PRTL_UNICODE_STRING_BUFFER)UnicodeStringOrUnicodeStringBuffer)->String;
469 }
470 else
471 {
472 DPRINT1("ERROR: Type = %u\n", Type);
474 }
475
476 Length = 0;
477 Status = LengthFunction(0, String, &Length);
478 if (!NT_SUCCESS(Status))
479 return Status;
480
483
484 String->Length = (USHORT)(Length * sizeof(WCHAR));
485
486 if (Type == sizeof(RTL_UNICODE_STRING_BUFFER))
487 {
488 String->Buffer[Length] = UNICODE_NULL;
489 }
490
491 return STATUS_SUCCESS;
492}
493
495NTAPI
498 OUT PULONG LengthOut)
499{
500 static const UNICODE_STRING PathDividers = RTL_CONSTANT_STRING(L"\\/");
503
504 /* All failure paths have this in common, so simplify code */
505 if (LengthOut)
506 *LengthOut = 0;
507
508 if (Flags || !Path || !LengthOut)
509 {
511 }
512
513 if ((Path->Length / sizeof(WCHAR)) == 0)
514 {
515 /* Nothing to do here */
516 return STATUS_SUCCESS;
517 }
518
519
521 switch (PathType)
522 {
524 // Handle \\\\?\\C:\\ with the last ':' or '\\' missing:
525 if (Path->Length / sizeof(WCHAR) < 7 ||
526 Path->Buffer[5] != ':' ||
527 !IS_PATH_SEPARATOR(Path->Buffer[6]))
528 {
530 }
531 break;
533 // "\\??\\"
534 break;
536 // "\\\\"
537 break;
539 // "C:\\"
540 break;
541 default:
543 }
544
545 /* Find the last path separator */
547 Position = 0;
548
549 /* Is it the last char of the string? */
550 if (Position && Position + sizeof(WCHAR) == Path->Length)
551 {
552 UNICODE_STRING Tmp = *Path;
553 Tmp.Length = Position;
554
555 /* Keep walking path separators to eliminate multiple next to eachother */
556 while (Tmp.Length > sizeof(WCHAR) && IS_PATH_SEPARATOR(Tmp.Buffer[Tmp.Length / sizeof(WCHAR)]))
557 Tmp.Length -= sizeof(WCHAR);
558
559 /* Find the previous occurence */
561 Position = 0;
562 }
563
564 /* Simplify code by working in chars instead of bytes */
565 if (Position)
566 Position /= sizeof(WCHAR);
567
568 if (Position)
569 {
570 // Keep walking path separators to eliminate multiple next to eachother, but ensure we leave one in place!
571 while (Position > 1 && IS_PATH_SEPARATOR(Path->Buffer[Position - 1]))
572 Position--;
573 }
574
575 if (Position > 0)
576 {
577 /* Return a length, not an index */
578 *LengthOut = Position + 1;
579 }
580
581 return STATUS_SUCCESS;
582}
583
585NTAPI
587 _In_ PUNICODE_STRING DllName,
588 _Inout_ PUNICODE_STRING RealName,
589 _Inout_ PUNICODE_STRING LocalName)
590{
591 static const UNICODE_STRING ExtensionChar = RTL_CONSTANT_STRING(L".");
592
594 UNICODE_STRING ImagePathName, DllNameOnly, CopyRealName, CopyLocalName;
595 BOOLEAN HasExtension;
598 C_ASSERT(sizeof(UNICODE_NULL) == sizeof(WCHAR));
599
600 CopyRealName = *RealName;
601 CopyLocalName = *LocalName;
602
603
604 /* Get the image path */
606
607 /* Check if it's not normalized */
608 if (!(RtlGetCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
609 {
610 /* Normalize it */
611 ImagePathName.Buffer = (PWSTR)((ULONG_PTR)ImagePathName.Buffer + (ULONG_PTR)RtlGetCurrentPeb()->ProcessParameters);
612 }
613
614
616 DllName, &RtlpPathDividers, &Position)))
617 {
618 DllNameOnly = *DllName;
619 }
620 else
621 {
622 /* Just keep the dll name, ignore path components */
623 Position += sizeof(WCHAR);
624 DllNameOnly.Buffer = DllName->Buffer + Position / sizeof(WCHAR);
625 DllNameOnly.Length = DllName->Length - Position;
626 DllNameOnly.MaximumLength = DllName->MaximumLength - Position;
627 }
628
630 &DllNameOnly, &ExtensionChar, &Position)))
631 {
632 Position = 0;
633 }
634
635 HasExtension = Position > 1;
636
637 /* First we create the c:\path\processname.exe.Local\something.dll path */
638 RequiredSize = ImagePathName.Length + RtlpDotLocal.Length + DllNameOnly.Length +
639 (HasExtension ? 0 : RtlpDefaultExtension.Length) + sizeof(UNICODE_NULL);
640
641 /* This is not going to work out */
644
645 /* We need something extra */
646 if (RequiredSize > CopyLocalName.MaximumLength)
647 {
649 if (CopyLocalName.Buffer == NULL)
650 return STATUS_NO_MEMORY;
651 CopyLocalName.MaximumLength = RequiredSize;
652 }
653 /* Now build the entire path */
654 CopyLocalName.Length = 0;
655 Status = RtlAppendUnicodeStringToString(&CopyLocalName, &ImagePathName);
657 if (NT_SUCCESS(Status))
658 {
661 }
662 if (NT_SUCCESS(Status))
663 {
664 Status = RtlAppendUnicodeStringToString(&CopyLocalName, &DllNameOnly);
666 }
667 /* Do we need to append an extension? */
668 if (NT_SUCCESS(Status) && !HasExtension)
669 {
672 }
673
674 if (NT_SUCCESS(Status))
675 {
676 /* then we create the c:\path\something.dll path */
678 &ImagePathName, &RtlpPathDividers, &Position)))
679 {
680 ImagePathName.Length = Position + sizeof(WCHAR);
681 }
682
683 RequiredSize = ImagePathName.Length + DllNameOnly.Length +
684 (HasExtension ? 0 : RtlpDefaultExtension.Length) + sizeof(UNICODE_NULL);
685
687 {
689 }
690 else
691 {
692 if (RequiredSize > CopyRealName.MaximumLength)
693 {
695 if (CopyRealName.Buffer == NULL)
697 CopyRealName.MaximumLength = RequiredSize;
698 }
699 CopyRealName.Length = 0;
700 if (NT_SUCCESS(Status))
701 {
702 Status = RtlAppendUnicodeStringToString(&CopyRealName, &ImagePathName);
704 }
705 if (NT_SUCCESS(Status))
706 {
707 Status = RtlAppendUnicodeStringToString(&CopyRealName, &DllNameOnly);
709 }
710 if (NT_SUCCESS(Status) && !HasExtension)
711 {
714 }
715 }
716 }
717
718 if (!NT_SUCCESS(Status))
719 {
720 if (CopyRealName.Buffer && CopyRealName.Buffer != RealName->Buffer)
721 RtlpFreeStringMemory(CopyRealName.Buffer, TAG_USTR);
722 if (CopyLocalName.Buffer && CopyLocalName.Buffer != LocalName->Buffer)
723 RtlpFreeStringMemory(CopyLocalName.Buffer, TAG_USTR);
724 return Status;
725 }
726
727 *RealName = CopyRealName;
728 *LocalName = CopyLocalName;
729 return STATUS_SUCCESS;
730}
731
732ULONG
733NTAPI
741{
744 ULONG FileNameLength, FileNameChars, DosLength, DosLengthOffset, FullLength;
745 BOOLEAN SkipTrailingPathSeparators;
746 WCHAR c;
747
748
749 ULONG reqsize = 0;
750 PCWSTR ptr;
751
752 PCUNICODE_STRING CurDirName;
753 UNICODE_STRING EnvVarName, EnvVarValue;
754 WCHAR EnvVarNameBuffer[4];
755
756 ULONG PrefixCut = 0; // Where the path really starts (after the skipped prefix)
757 PWCHAR Prefix = NULL; // pointer to the string to be inserted as the new path prefix
758 ULONG PrefixLength = 0;
760 ULONG SourceLength;
761
762
763 /* For now, assume the name is valid */
764 DPRINT("Filename: %wZ\n", FileName);
765 DPRINT("Size and buffer: %lx %p\n", Size, Buffer);
767
768 /* Handle initial path type and failure case */
770 if ((FileName->Length == 0) || (FileName->Buffer[0] == UNICODE_NULL)) return 0;
771
772 /* Break filename into component parts */
773 FileNameBuffer = FileName->Buffer;
774 FileNameLength = FileName->Length;
775 FileNameChars = FileNameLength / sizeof(WCHAR);
776
777 /* Kill trailing spaces */
778 c = FileNameBuffer[FileNameChars - 1];
779 while ((FileNameLength != 0) && (c == L' '))
780 {
781 /* Keep going, ignoring the spaces */
782 FileNameLength -= sizeof(WCHAR);
783 if (FileNameLength != 0) c = FileNameBuffer[FileNameLength / sizeof(WCHAR) - 1];
784 }
785
786 /* Check if anything is left */
787 if (FileNameLength == 0) return 0;
788
789 /*
790 * Check whether we'll need to skip trailing path separators in the
791 * computed full path name. If the original file name already contained
792 * trailing separators, then we keep them in the full path name. On the
793 * other hand, if the original name didn't contain any trailing separators
794 * then we'll skip it in the full path name.
795 */
796 SkipTrailingPathSeparators = !IS_PATH_SEPARATOR(FileNameBuffer[FileNameChars - 1]);
797
798 /* Check if this is a DOS name */
800 DPRINT("DOS length for filename: %lx %wZ\n", DosLength, FileName);
801 if (DosLength != 0)
802 {
803 /* Zero out the short name */
804 if (ShortName) *ShortName = NULL;
805
806 /* See comment for RtlIsDosDeviceName_Ustr if this is confusing... */
807 DosLengthOffset = HIWORD(DosLength);
808 DosLength = LOWORD(DosLength);
809
810 /* Do we have a DOS length, and does the caller want validity? */
811 if (InvalidName && (DosLengthOffset != 0))
812 {
813 /* Do the check */
814 Status = RtlpCheckDeviceName(FileName, DosLengthOffset, InvalidName);
815
816 /* If the check failed, or the name is invalid, fail here */
817 if (!NT_SUCCESS(Status)) return 0;
818 if (*InvalidName) return 0;
819 }
820
821 /* Add the size of the device root and check if it fits in the size */
822 FullLength = DosLength + DeviceRootString.Length;
823 if (FullLength < Size)
824 {
825 /* Add the device string */
827
828 /* Now add the DOS device name */
830 (PCHAR)FileNameBuffer + DosLengthOffset,
831 DosLength);
832
833 /* Null terminate */
834 *(PWCHAR)((ULONG_PTR)Buffer + FullLength) = UNICODE_NULL;
835 return FullLength;
836 }
837
838 /* Otherwise, there's no space, so return the buffer size needed */
839 if ((FullLength + sizeof(UNICODE_NULL)) > UNICODE_STRING_MAX_BYTES) return 0;
840 return FullLength + sizeof(UNICODE_NULL);
841 }
842
843 /* Zero-out the destination buffer. FileName must be different from Buffer */
845
846 /* Get the path type */
848
849
850
851 /**********************************************
852 ** CODE REWRITING IS HAPPENING THERE **
853 **********************************************/
855 SourceLength = FileNameLength;
856 EnvVarValue.Buffer = NULL;
857
858 /* Lock the PEB to get the current directory */
860 CurDirName = &NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath;
861
862 switch (*PathType)
863 {
864 case RtlPathTypeUncAbsolute: /* \\foo */
865 {
867 break;
868 }
869
870 case RtlPathTypeLocalDevice: /* \\.\foo */
871 {
872 PrefixCut = 4;
873 break;
874 }
875
876 case RtlPathTypeDriveAbsolute: /* c:\foo */
877 {
878 ASSERT(FileNameBuffer[1] == L':');
880
881 // FileNameBuffer[0] = RtlpUpcaseUnicodeChar(FileNameBuffer[0]);
883 PrefixLength = 3 * sizeof(WCHAR);
884 Source += 3;
885 SourceLength -= 3 * sizeof(WCHAR);
886
887 PrefixCut = 3;
888 break;
889 }
890
891 case RtlPathTypeDriveRelative: /* c:foo */
892 {
893 WCHAR CurDrive, NewDrive;
894
895 Source += 2;
896 SourceLength -= 2 * sizeof(WCHAR);
897
898 CurDrive = RtlpUpcaseUnicodeChar(CurDirName->Buffer[0]);
900
901 if ((NewDrive != CurDrive) || CurDirName->Buffer[1] != L':')
902 {
903 EnvVarNameBuffer[0] = L'=';
904 EnvVarNameBuffer[1] = NewDrive;
905 EnvVarNameBuffer[2] = L':';
906 EnvVarNameBuffer[3] = UNICODE_NULL;
907
908 EnvVarName.Length = 3 * sizeof(WCHAR);
909 EnvVarName.MaximumLength = EnvVarName.Length + sizeof(WCHAR);
910 EnvVarName.Buffer = EnvVarNameBuffer;
911
912 // FIXME: Is it possible to use the user-given buffer ?
913 // RtlInitEmptyUnicodeString(&EnvVarValue, NULL, Size);
914 EnvVarValue.Length = 0;
915 EnvVarValue.MaximumLength = (USHORT)Size;
916 EnvVarValue.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
917 if (EnvVarValue.Buffer == NULL)
918 {
919 Prefix = NULL;
920 PrefixLength = 0;
921 goto Quit;
922 }
923
924 Status = RtlQueryEnvironmentVariable_U(NULL, &EnvVarName, &EnvVarValue);
925 switch (Status)
926 {
927 case STATUS_SUCCESS:
928 /*
929 * (From Wine)
930 * FIXME: Win2k seems to check that the environment
931 * variable actually points to an existing directory.
932 * If not, root of the drive is used (this seems also
933 * to be the only place in RtlGetFullPathName that the
934 * existence of a part of a path is checked).
935 */
936 EnvVarValue.Buffer[EnvVarValue.Length / sizeof(WCHAR)] = L'\\';
937 Prefix = EnvVarValue.Buffer;
938 PrefixLength = EnvVarValue.Length + sizeof(WCHAR); /* Append trailing '\\' */
939 break;
940
942 reqsize = EnvVarValue.Length + SourceLength + sizeof(UNICODE_NULL);
943 goto Quit;
944
945 default:
946 DPRINT1("RtlQueryEnvironmentVariable_U(\"%wZ\") returned 0x%08lx\n", &EnvVarName, Status);
947
948 EnvVarNameBuffer[0] = NewDrive;
949 EnvVarNameBuffer[1] = L':';
950 EnvVarNameBuffer[2] = L'\\';
951 EnvVarNameBuffer[3] = UNICODE_NULL;
952 Prefix = EnvVarNameBuffer;
953 PrefixLength = 3 * sizeof(WCHAR);
954
955 RtlFreeHeap(RtlGetProcessHeap(), 0, EnvVarValue.Buffer);
956 EnvVarValue.Buffer = NULL;
957 break;
958 }
959 PrefixCut = 3;
960 break;
961 }
962 /* Fall through */
963 DPRINT("RtlPathTypeDriveRelative - Using fall-through to RtlPathTypeRelative\n");
964 }
965
966 case RtlPathTypeRelative: /* foo */
967 {
968 Prefix = CurDirName->Buffer;
969 PrefixLength = CurDirName->Length;
970 if (CurDirName->Buffer[1] != L':')
971 {
972 PrefixCut = RtlpSkipUNCPrefix(CurDirName->Buffer);
973 }
974 else
975 {
976 PrefixCut = 3;
977 }
978 break;
979 }
980
981 case RtlPathTypeRooted: /* \xxx */
982 {
983 if (CurDirName->Buffer[1] == L':')
984 {
985 // The path starts with "C:\"
986 ASSERT(CurDirName->Buffer[1] == L':');
987 ASSERT(IS_PATH_SEPARATOR(CurDirName->Buffer[2]));
988
989 Prefix = CurDirName->Buffer;
990 PrefixLength = 3 * sizeof(WCHAR); // Skip "C:\"
991
992 PrefixCut = 3; // Source index location incremented of + 3
993 }
994 else
995 {
996 PrefixCut = RtlpSkipUNCPrefix(CurDirName->Buffer);
997 PrefixLength = PrefixCut * sizeof(WCHAR);
998 Prefix = CurDirName->Buffer;
999 }
1000 break;
1001 }
1002
1003 case RtlPathTypeRootLocalDevice: /* \\. */
1004 {
1006 PrefixLength = DeviceRootString.Length;
1007 Source += 3;
1008 SourceLength -= 3 * sizeof(WCHAR);
1009
1010 PrefixCut = 4;
1011 break;
1012 }
1013
1014 case RtlPathTypeUnknown:
1015 goto Quit;
1016 }
1017
1018 /* Do we have enough space for storing the full path? */
1019 reqsize = PrefixLength;
1020 if (reqsize + SourceLength + sizeof(WCHAR) > Size)
1021 {
1022 /* Not enough space, return needed size (including terminating '\0') */
1023 reqsize += SourceLength + sizeof(WCHAR);
1024 goto Quit;
1025 }
1026
1027 /*
1028 * Build the full path
1029 */
1030 /* Copy the path's prefix */
1031 if (PrefixLength) RtlMoveMemory(Buffer, Prefix, PrefixLength);
1032 /* Copy the remaining part of the path */
1033 RtlMoveMemory(Buffer + PrefixLength / sizeof(WCHAR), Source, SourceLength + sizeof(WCHAR));
1034
1035 /* Some cleanup */
1036 Prefix = NULL;
1037 if (EnvVarValue.Buffer)
1038 {
1039 RtlFreeHeap(RtlGetProcessHeap(), 0, EnvVarValue.Buffer);
1040 EnvVarValue.Buffer = NULL;
1041 }
1042
1043 /*
1044 * Finally, put the path in canonical form (remove redundant . and ..,
1045 * (back)slashes...) and retrieve the length of the full path name
1046 * (without its terminating null character) (in chars).
1047 */
1048 reqsize = RtlpCollapsePath(Buffer, /* Size, reqsize, */ PrefixCut, SkipTrailingPathSeparators);
1049
1050 /* Find the file part, which is present after the last path separator */
1051 if (ShortName)
1052 {
1053 ptr = wcsrchr(Buffer, L'\\');
1054 if (ptr) ++ptr; // Skip it
1055
1056 /*
1057 * For UNC paths, the file part is after the \\share\dir part of the path.
1058 */
1059 PrefixCut = (*PathType == RtlPathTypeUncAbsolute ? PrefixCut : 3);
1060
1061 if (ptr && *ptr && (ptr >= Buffer + PrefixCut))
1062 {
1063 *ShortName = ptr;
1064 }
1065 else
1066 {
1067 /* Zero-out the short name */
1068 *ShortName = NULL;
1069 }
1070 }
1071
1072Quit:
1073 /* Release PEB lock */
1075
1076 return reqsize;
1077}
1078
1080NTAPI
1082 OUT PUNICODE_STRING NtPath,
1083 OUT PCWSTR *PartName,
1084 OUT PRTL_RELATIVE_NAME_U RelativeName)
1085{
1086 ULONG DosLength;
1087 PWSTR NewBuffer, p;
1088
1089 /* Validate the input */
1090 if (!DosPath) return STATUS_OBJECT_NAME_INVALID;
1091
1092 /* Validate the DOS length */
1093 DosLength = DosPath->Length;
1094 if (DosLength >= UNICODE_STRING_MAX_BYTES) return STATUS_NAME_TOO_LONG;
1095
1096 /* Make space for the new path */
1097 NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
1098 0,
1099 DosLength + sizeof(UNICODE_NULL));
1100 if (!NewBuffer) return STATUS_NO_MEMORY;
1101
1102 /* Copy the prefix, and then the rest of the DOS path, and NULL-terminate */
1105 DosPath->Buffer + RtlpDosDevicesPrefix.Length / sizeof(WCHAR),
1106 DosPath->Length - RtlpDosDevicesPrefix.Length);
1107 NewBuffer[DosLength / sizeof(WCHAR)] = UNICODE_NULL;
1108
1109 /* Did the caller send a relative name? */
1110 if (RelativeName)
1111 {
1112 /* Zero initialize it */
1113 RtlInitEmptyUnicodeString(&RelativeName->RelativeName, NULL, 0);
1114 RelativeName->ContainingDirectory = NULL;
1115 RelativeName->CurDirRef = 0;
1116 }
1117
1118 /* Did the caller request a partial name? */
1119 if (PartName)
1120 {
1121 /* Loop from the back until we find a path separator */
1122 p = &NewBuffer[DosLength / sizeof(WCHAR)];
1123 while (--p > NewBuffer)
1124 {
1125 /* We found a path separator, move past it */
1126 if (*p == OBJ_NAME_PATH_SEPARATOR)
1127 {
1128 ++p;
1129 break;
1130 }
1131 }
1132
1133 /* Check whether a separator was found and if something remains */
1134 if ((p > NewBuffer) && *p)
1135 {
1136 /* What follows the path separator is the partial name */
1137 *PartName = p;
1138 }
1139 else
1140 {
1141 /* The path ends with a path separator, no partial name */
1142 *PartName = NULL;
1143 }
1144 }
1145
1146 /* Build the final NT path string */
1147 NtPath->Buffer = NewBuffer;
1148 NtPath->Length = (USHORT)DosLength;
1149 NtPath->MaximumLength = (USHORT)DosLength + sizeof(UNICODE_NULL);
1150 return STATUS_SUCCESS;
1151}
1152
1154NTAPI
1157 OUT PUNICODE_STRING NtName,
1158 OUT PCWSTR *PartName,
1159 OUT PRTL_RELATIVE_NAME_U RelativeName)
1160{
1161 WCHAR BigBuffer[MAX_PATH + 1];
1162 PWCHAR PrefixBuffer, NewBuffer, Buffer;
1163 ULONG MaxLength, PathLength, PrefixLength, PrefixCut, LengthChars, Length;
1164 UNICODE_STRING CapturedDosName, PartNameString, FullPath;
1165 BOOLEAN QuickPath;
1166 RTL_PATH_TYPE InputPathType, BufferPathType;
1170
1171 /* Assume MAX_PATH for now */
1172 DPRINT("Relative: %lx DosName: %wZ NtName: %p, PartName: %p, RelativeName: %p\n",
1173 HaveRelative, DosName, NtName, PartName, RelativeName);
1174 MaxLength = sizeof(BigBuffer);
1175
1176 /* Validate the input */
1178
1179 /* Capture input string */
1180 CapturedDosName = *DosName;
1181
1182 /* Check for the presence or absence of the NT prefix "\\?\" form */
1183 // if (!RtlPrefixUnicodeString(&RtlpWin32NtRootSlash, &CapturedDosName, FALSE))
1184 if ((CapturedDosName.Length <= RtlpWin32NtRootSlash.Length) ||
1185 (CapturedDosName.Buffer[0] != RtlpWin32NtRootSlash.Buffer[0]) ||
1186 (CapturedDosName.Buffer[1] != RtlpWin32NtRootSlash.Buffer[1]) ||
1187 (CapturedDosName.Buffer[2] != RtlpWin32NtRootSlash.Buffer[2]) ||
1188 (CapturedDosName.Buffer[3] != RtlpWin32NtRootSlash.Buffer[3]))
1189 {
1190 /* NT prefix not present */
1191
1192 /* Quick path won't be used */
1193 QuickPath = FALSE;
1194
1195 /* Use the static buffer */
1196 Buffer = BigBuffer;
1197 MaxLength += RtlpDosDevicesUncPrefix.Length;
1198
1199 /* Allocate a buffer to hold the path */
1200 NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, MaxLength);
1201 DPRINT("MaxLength: %lx\n", MaxLength);
1202 if (!NewBuffer) return STATUS_NO_MEMORY;
1203 }
1204 else
1205 {
1206 /* NT prefix present */
1207
1208 /* Use the optimized path after acquiring the lock */
1209 QuickPath = TRUE;
1210 NewBuffer = NULL;
1211 }
1212
1213 /* Lock the PEB and check if the quick path can be used */
1215 if (QuickPath)
1216 {
1217 /* Some simple fixups will get us the correct path */
1218 DPRINT("Quick path\n");
1219 Status = RtlpWin32NTNameToNtPathName_U(&CapturedDosName,
1220 NtName,
1221 PartName,
1222 RelativeName);
1223
1224 /* Release the lock, we're done here */
1226 return Status;
1227 }
1228
1229 /* Call the main function to get the full path name and length */
1230 PathLength = RtlGetFullPathName_Ustr(&CapturedDosName,
1231 MAX_PATH * sizeof(WCHAR),
1232 Buffer,
1233 PartName,
1234 &NameInvalid,
1235 &InputPathType);
1236 if ((NameInvalid) || !(PathLength) || (PathLength > (MAX_PATH * sizeof(WCHAR))))
1237 {
1238 /* Invalid name, fail */
1239 DPRINT("Invalid name: %lx Path Length: %lx\n", NameInvalid, PathLength);
1240 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
1243 }
1244
1245 /* Start by assuming the path starts with \??\ (DOS Devices Path) */
1246 PrefixLength = RtlpDosDevicesPrefix.Length;
1247 PrefixBuffer = RtlpDosDevicesPrefix.Buffer;
1248 PrefixCut = 0;
1249
1250 /* Check where it really is */
1251 BufferPathType = RtlDetermineDosPathNameType_U(Buffer);
1252 DPRINT("Buffer: %S Type: %lx\n", Buffer, BufferPathType);
1253 switch (BufferPathType)
1254 {
1255 /* It's actually a UNC path in \??\UNC\ */
1257 PrefixLength = RtlpDosDevicesUncPrefix.Length;
1258 PrefixBuffer = RtlpDosDevicesUncPrefix.Buffer;
1259 PrefixCut = 2;
1260 break;
1261
1263 /* We made a good guess, go with it but skip the \??\ */
1264 PrefixCut = 4;
1265 break;
1266
1269 case RtlPathTypeRooted:
1271 /* Our guess was good, roll with it */
1272 break;
1273
1274 /* Nothing else is expected */
1275 default:
1276 ASSERT(FALSE);
1277 }
1278
1279 /* Now copy the prefix and the buffer */
1280 RtlCopyMemory(NewBuffer, PrefixBuffer, PrefixLength);
1281 RtlCopyMemory((PCHAR)NewBuffer + PrefixLength,
1282 Buffer + PrefixCut,
1283 PathLength - (PrefixCut * sizeof(WCHAR)));
1284
1285 /* Compute the length */
1286 Length = PathLength + PrefixLength - PrefixCut * sizeof(WCHAR);
1287 LengthChars = Length / sizeof(WCHAR);
1288
1289 /* Setup the actual NT path string and terminate it */
1290 NtName->Buffer = NewBuffer;
1291 NtName->Length = (USHORT)Length;
1292 NtName->MaximumLength = (USHORT)MaxLength;
1293 NewBuffer[LengthChars] = UNICODE_NULL;
1294 DPRINT("New buffer: %S\n", NewBuffer);
1295 DPRINT("NT Name: %wZ\n", NtName);
1296
1297 /* Check if a partial name was requested */
1298 if ((PartName) && (*PartName))
1299 {
1300 /* Convert to Unicode */
1301 Status = RtlInitUnicodeStringEx(&PartNameString, *PartName);
1302 if (NT_SUCCESS(Status))
1303 {
1304 /* Set the partial name */
1305 *PartName = &NewBuffer[LengthChars - (PartNameString.Length / sizeof(WCHAR))];
1306 }
1307 else
1308 {
1309 /* Fail */
1310 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
1312 return Status;
1313 }
1314 }
1315
1316 /* Check if a relative name was asked for */
1317 if (RelativeName)
1318 {
1319 /* Setup the structure */
1320 RtlInitEmptyUnicodeString(&RelativeName->RelativeName, NULL, 0);
1321 RelativeName->ContainingDirectory = NULL;
1322 RelativeName->CurDirRef = NULL;
1323
1324 /* Check if the input path itself was relative */
1325 if (InputPathType == RtlPathTypeRelative)
1326 {
1327 /* Get current directory */
1328 CurrentDirectory = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
1329 if (CurrentDirectory->Handle)
1330 {
1331 Status = RtlInitUnicodeStringEx(&FullPath, Buffer);
1332 if (!NT_SUCCESS(Status))
1333 {
1334 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
1336 return Status;
1337 }
1338
1339 /* If current directory is bigger than full path, there's no way */
1340 if (CurrentDirectory->DosPath.Length > FullPath.Length)
1341 {
1343 return Status;
1344 }
1345
1346 /* File is in current directory */
1347 if (RtlEqualUnicodeString(&FullPath, &CurrentDirectory->DosPath, TRUE))
1348 {
1349 /* Make relative name string */
1350 RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)NewBuffer + PrefixLength + FullPath.Length - PrefixCut * sizeof(WCHAR));
1351 RelativeName->RelativeName.Length = (USHORT)(PathLength - FullPath.Length);
1352 /* If relative name starts with \, skip it */
1353 if (RelativeName->RelativeName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
1354 {
1355 RelativeName->RelativeName.Buffer++;
1356 RelativeName->RelativeName.Length -= sizeof(WCHAR);
1357 }
1358 RelativeName->RelativeName.MaximumLength = RelativeName->RelativeName.Length;
1359 DPRINT("RelativeName: %wZ\n", &(RelativeName->RelativeName));
1360
1361 if (!HaveRelative)
1362 {
1363 RelativeName->ContainingDirectory = CurrentDirectory->Handle;
1364 return Status;
1365 }
1366
1367 /* Give back current directory data & reference counter */
1368 RelativeName->CurDirRef = RtlpCurDirRef;
1369 if (RelativeName->CurDirRef)
1370 {
1372 }
1373
1374 RelativeName->ContainingDirectory = CurrentDirectory->Handle;
1375 }
1376 }
1377 }
1378 }
1379
1380 /* Done */
1382 return STATUS_SUCCESS;
1383}
1384
1386NTAPI
1389 OUT PUNICODE_STRING NtName,
1390 OUT PCWSTR *PartName,
1391 OUT PRTL_RELATIVE_NAME_U RelativeName)
1392{
1394 UNICODE_STRING NameString;
1395
1396 /* Create the unicode name */
1397 Status = RtlInitUnicodeStringEx(&NameString, DosName);
1398 if (NT_SUCCESS(Status))
1399 {
1400 /* Call the unicode function */
1402 &NameString,
1403 NtName,
1404 PartName,
1405 RelativeName);
1406 }
1407
1408 /* Return status */
1409 return Status;
1410}
1411
1412BOOLEAN
1413NTAPI
1415 OUT PUNICODE_STRING NtName,
1416 OUT PCWSTR *PartName,
1417 OUT PRTL_RELATIVE_NAME_U RelativeName)
1418{
1419 /* Call the internal function */
1420 ASSERT(RelativeName);
1422 DosName,
1423 NtName,
1424 PartName,
1425 RelativeName));
1426}
1427
1428BOOLEAN
1429NTAPI
1432{
1434 RTL_RELATIVE_NAME_U RelativeName;
1435 UNICODE_STRING NtPathName;
1436 PVOID Buffer;
1439 FILE_BASIC_INFORMATION BasicInformation;
1440
1441 /* Get the NT Path */
1443 &NtPathName,
1444 NULL,
1445 &RelativeName);
1446 if (!Result) return FALSE;
1447
1448 /* Save the buffer */
1449 Buffer = NtPathName.Buffer;
1450
1451 /* Check if we have a relative name */
1452 if (RelativeName.RelativeName.Length)
1453 {
1454 /* Use it */
1455 NtPathName = RelativeName.RelativeName;
1456 }
1457 else
1458 {
1459 /* Otherwise ignore it */
1460 RelativeName.ContainingDirectory = NULL;
1461 }
1462
1463 /* Initialize the object attributes */
1465 &NtPathName,
1467 RelativeName.ContainingDirectory,
1468 NULL);
1469
1470 /* Query the attributes and free the buffer now */
1471 Status = ZwQueryAttributesFile(&ObjectAttributes, &BasicInformation);
1472 RtlReleaseRelativeName(&RelativeName);
1473 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1474
1475 /* Check if we failed */
1476 if (!NT_SUCCESS(Status))
1477 {
1478 /* Check if we failed because the file is in use */
1481 {
1482 /* Check if the caller wants this to be considered OK */
1484 }
1485 else
1486 {
1487 /* A failure because the file didn't exist */
1488 Result = FALSE;
1489 }
1490 }
1491 else
1492 {
1493 /* The file exists */
1494 Result = TRUE;
1495 }
1496
1497 /* Return the result */
1498 return Result;
1499}
1500
1501BOOLEAN
1502NTAPI
1504{
1505 /* Call the updated API */
1507}
1508
1509BOOLEAN
1510NTAPI
1513{
1514 UNICODE_STRING NameString;
1515
1516 /* Create the unicode name*/
1517 if (NT_SUCCESS(RtlInitUnicodeStringEx(&NameString, FileName)))
1518 {
1519 /* Call the unicode function */
1520 return RtlDoesFileExists_UstrEx(&NameString, SucceedIfBusy);
1521 }
1522
1523 /* Fail */
1524 return FALSE;
1525}
1526
1527/* PUBLIC FUNCTIONS ***********************************************************/
1528
1529/*
1530 * @implemented
1531 */
1532VOID
1533NTAPI
1535{
1536 /* Check if a directory reference was grabbed */
1537 if (RelativeName->CurDirRef)
1538 {
1539 /* Decrease reference count */
1540 if (!InterlockedDecrement(&RelativeName->CurDirRef->RefCount))
1541 {
1542 /* If no one uses it any longer, close handle & free */
1543 NtClose(RelativeName->CurDirRef->Handle);
1544 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeName->CurDirRef);
1545 }
1546 RelativeName->CurDirRef = NULL;
1547 }
1548}
1549
1550/*
1551 * @implemented
1552 */
1553ULONG
1554NTAPI
1556{
1557 /*
1558 * The longest NT path is a DOS path that actually sits on a UNC path (ie:
1559 * a mapped network drive), which is accessed through the DOS Global?? path.
1560 * This is, and has always been equal to, 269 characters, except in Wine
1561 * which claims this is 277. Go figure.
1562 */
1563 return MAX_PATH + RtlpDosDevicesUncPrefix.Length / sizeof(WCHAR) + sizeof(ANSI_NULL);
1564}
1565
1566/*
1567 * @implemented
1568 * @note: the export is called RtlGetLengthWithoutTrailingPathSeperators
1569 * (with a 'e' instead of a 'a' in "Seperators").
1570 */
1572NTAPI
1574 IN PCUNICODE_STRING PathString,
1576{
1577 ULONG NumChars;
1578
1579 /* Parameters validation */
1580 if (Length == NULL) return STATUS_INVALID_PARAMETER;
1581
1582 *Length = 0;
1583
1584 if (PathString == NULL) return STATUS_INVALID_PARAMETER;
1585
1586 /* No flags are supported yet */
1587 if (Flags != 0) return STATUS_INVALID_PARAMETER;
1588
1589 NumChars = PathString->Length / sizeof(WCHAR);
1590
1591 /*
1592 * Notice that we skip the last character, therefore:
1593 * - if we have: "some/path/f" we test for: "some/path/"
1594 * - if we have: "some/path/" we test for: "some/path"
1595 * - if we have: "s" we test for: ""
1596 * - if we have: "" then NumChars was already zero and we aren't there
1597 */
1598
1599 while (NumChars > 0 && IS_PATH_SEPARATOR(PathString->Buffer[NumChars - 1]))
1600 {
1601 --NumChars;
1602 }
1603
1604 *Length = NumChars;
1605 return STATUS_SUCCESS;
1606}
1607
1608/*
1609 * @implemented
1610 */
1612NTAPI
1614{
1615 DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
1616
1617 /* Unlike the newer RtlDetermineDosPathNameType_U we assume 4 characters */
1618 if (IS_PATH_SEPARATOR(Path[0]))
1619 {
1620 if (!IS_PATH_SEPARATOR(Path[1])) return RtlPathTypeRooted; /* \x */
1621 if ((Path[2] != L'.') && (Path[2] != L'?')) return RtlPathTypeUncAbsolute;/* \\x */
1622 if (IS_PATH_SEPARATOR(Path[3])) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */
1623 if (Path[3]) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */
1624 return RtlPathTypeRootLocalDevice; /* \\. or \\? */
1625 }
1626 else
1627 {
1628 if (!(Path[0]) || (Path[1] != L':')) return RtlPathTypeRelative; /* x */
1629 if (IS_PATH_SEPARATOR(Path[2])) return RtlPathTypeDriveAbsolute; /* x:\ */
1630 return RtlPathTypeDriveRelative; /* x: */
1631 }
1632}
1633
1634/*
1635 * @implemented
1636 */
1637ULONG
1638NTAPI
1640{
1641 UNICODE_STRING PathString;
1643
1644 /* Build the string */
1645 Status = RtlInitUnicodeStringEx(&PathString, Path);
1646 if (!NT_SUCCESS(Status)) return 0;
1647
1648 /*
1649 * Returns 0 if name is not valid DOS device name, or DWORD with
1650 * offset in bytes to DOS device name from beginning of buffer in high word
1651 * and size in bytes of DOS device name in low word
1652 */
1653 return RtlIsDosDeviceName_Ustr(&PathString);
1654}
1655
1656/*
1657 * @implemented
1658 */
1659ULONG
1660NTAPI
1664{
1666 PCURDIR CurDir;
1667 PWSTR CurDirName;
1668 DPRINT("RtlGetCurrentDirectory %lu %p\n", MaximumLength, Buffer);
1669
1670 /* Lock the PEB to get the current directory */
1672 CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory;
1673
1674 /* Get the buffer and character length */
1675 CurDirName = CurDir->DosPath.Buffer;
1676 Length = CurDir->DosPath.Length / sizeof(WCHAR);
1677 ASSERT((CurDirName != NULL) && (Length > 0));
1678
1679 /*
1680 * DosPath.Buffer should always have a trailing slash. There is an assert
1681 * below which checks for this.
1682 *
1683 * This function either returns x:\ for a root (keeping the original buffer)
1684 * or it returns x:\path\foo for a directory (replacing the trailing slash
1685 * with a NULL.
1686 */
1687 Bytes = Length * sizeof(WCHAR);
1688 if ((Length <= 1) || (CurDirName[Length - 2] == L':'))
1689 {
1690 /* Check if caller does not have enough space */
1691 if (MaximumLength <= Bytes)
1692 {
1693 /* Call has no space for it, fail, add the trailing slash */
1695 return Bytes + sizeof(OBJ_NAME_PATH_SEPARATOR);
1696 }
1697 }
1698 else
1699 {
1700 /* Check if caller does not have enough space */
1701 if (MaximumLength < Bytes)
1702 {
1703 /* Call has no space for it, fail */
1705 return Bytes;
1706 }
1707 }
1708
1709 /* Copy the buffer since we seem to have space */
1710 RtlCopyMemory(Buffer, CurDirName, Bytes);
1711
1712 /* The buffer should end with a path separator */
1714
1715 /* Again check for our two cases (drive root vs path) */
1716 if ((Length <= 1) || (Buffer[Length - 2] != L':'))
1717 {
1718 /* Replace the trailing slash with a null */
1719 Buffer[Length - 1] = UNICODE_NULL;
1720 --Length;
1721 }
1722 else
1723 {
1724 /* Append the null char since there's no trailing slash */
1726 }
1727
1728 /* Release PEB lock */
1730 DPRINT("CurrentDirectory %S\n", Buffer);
1731 return Length * sizeof(WCHAR);
1732}
1733
1734/*
1735 * @implemented
1736 */
1738NTAPI
1740{
1741 PCURDIR CurDir;
1745 UNICODE_STRING FullPath, NtName;
1746 PRTLP_CURDIR_REF OldCurDir = NULL;
1748 FILE_FS_DEVICE_INFORMATION FileFsDeviceInfo;
1749 ULONG SavedLength, CharLength, FullPathLength;
1750 HANDLE OldHandle = NULL, CurDirHandle = NULL, OldCurDirHandle = NULL;
1751
1752 DPRINT("RtlSetCurrentDirectory_U %wZ\n", Path);
1753
1754 /* Initialize for failure case */
1755 RtlInitEmptyUnicodeString(&NtName, NULL, 0);
1756
1757 /* Can't set current directory on DOS device */
1759 {
1761 }
1762
1763 /* Get current directory */
1765 CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory;
1766
1767 /* Check if we have to drop current handle */
1769 {
1770 OldHandle = CurDir->Handle;
1771 CurDir->Handle = NULL;
1772 }
1773
1774 /* Allocate a buffer for full path (using max possible length */
1775 FullPath.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, CurDir->DosPath.MaximumLength);
1776 if (!FullPath.Buffer)
1777 {
1779 goto Leave;
1780 }
1781
1782 /* Init string */
1783 FullPath.Length = 0;
1784 FullPath.MaximumLength = CurDir->DosPath.MaximumLength;
1785
1786 /* Get new directory full path */
1787 FullPathLength = RtlGetFullPathName_Ustr(Path, FullPath.MaximumLength, FullPath.Buffer, NULL, NULL, &PathType);
1788 if (!FullPathLength)
1789 {
1791 goto Leave;
1792 }
1793
1794 SavedLength = FullPath.MaximumLength;
1795 CharLength = FullPathLength / sizeof(WCHAR);
1796
1797 if (FullPathLength > FullPath.MaximumLength)
1798 {
1800 goto Leave;
1801 }
1802
1803 /* Translate it to NT name */
1804 if (!RtlDosPathNameToNtPathName_U(FullPath.Buffer, &NtName, NULL, NULL))
1805 {
1807 goto Leave;
1808 }
1809
1812 NULL, NULL);
1813
1814 /* If previous current directory was removable, then check it for dropping */
1816 {
1817 /* Get back normal handle */
1818 CurDirHandle = (HANDLE)((ULONG_PTR)(CurDir->Handle) & ~RTL_CURDIR_ALL_FLAGS);
1819 CurDir->Handle = NULL;
1820
1821 /* Get device information */
1822 Status = NtQueryVolumeInformationFile(CurDirHandle,
1824 &FileFsDeviceInfo,
1825 sizeof(FileFsDeviceInfo),
1827 /* Retry without taking care of removable device */
1828 if (!NT_SUCCESS(Status))
1829 {
1831 goto Leave;
1832 }
1833 }
1834 else
1835 {
1836 /* Open directory */
1837 Status = NtOpenFile(&CurDirHandle,
1843 if (!NT_SUCCESS(Status)) goto Leave;
1844
1845 /* Get device information */
1846 Status = NtQueryVolumeInformationFile(CurDirHandle,
1848 &FileFsDeviceInfo,
1849 sizeof(FileFsDeviceInfo),
1851 if (!NT_SUCCESS(Status)) goto Leave;
1852 }
1853
1854 /* If device is removable, mark handle */
1855 if (FileFsDeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA)
1856 {
1857 CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_CURDIR_IS_REMOVABLE);
1858 }
1859
1860 FullPath.Length = (USHORT)FullPathLength;
1861
1862 /* If full path isn't \ terminated, do it */
1863 if (FullPath.Buffer[CharLength - 1] != OBJ_NAME_PATH_SEPARATOR)
1864 {
1865 if ((CharLength + 1) * sizeof(WCHAR) > SavedLength)
1866 {
1868 goto Leave;
1869 }
1870
1871 FullPath.Buffer[CharLength] = OBJ_NAME_PATH_SEPARATOR;
1872 FullPath.Buffer[CharLength + 1] = UNICODE_NULL;
1873 FullPath.Length += sizeof(WCHAR);
1874 }
1875
1876 /* If we have previous current directory with only us as reference, save it */
1877 if (RtlpCurDirRef != NULL && RtlpCurDirRef->RefCount == 1)
1878 {
1879 OldCurDirHandle = RtlpCurDirRef->Handle;
1880 }
1881 else
1882 {
1883 /* Allocate new current directory struct saving previous one */
1884 OldCurDir = RtlpCurDirRef;
1885 RtlpCurDirRef = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTLP_CURDIR_REF));
1886 if (!RtlpCurDirRef)
1887 {
1888 RtlpCurDirRef = OldCurDir;
1889 OldCurDir = NULL;
1891 goto Leave;
1892 }
1893
1894 /* Set reference to 1 (us) */
1896 }
1897
1898 /* Save new data */
1899 CurDir->Handle = CurDirHandle;
1900 RtlpCurDirRef->Handle = CurDirHandle;
1901 CurDirHandle = NULL;
1902
1903 /* Copy full path */
1904 RtlCopyMemory(CurDir->DosPath.Buffer, FullPath.Buffer, FullPath.Length + sizeof(WCHAR));
1905 CurDir->DosPath.Length = FullPath.Length;
1906
1908
1909Leave:
1911
1912 if (FullPath.Buffer)
1913 {
1914 RtlFreeHeap(RtlGetProcessHeap(), 0, FullPath.Buffer);
1915 }
1916
1917 if (NtName.Buffer)
1918 {
1919 RtlFreeHeap(RtlGetProcessHeap(), 0, NtName.Buffer);
1920 }
1921
1922 if (CurDirHandle) NtClose(CurDirHandle);
1923
1924 if (OldHandle) NtClose(OldHandle);
1925
1926 if (OldCurDirHandle) NtClose(OldCurDirHandle);
1927
1928 if (OldCurDir && InterlockedDecrement(&OldCurDir->RefCount) == 0)
1929 {
1930 NtClose(OldCurDir->Handle);
1931 RtlFreeHeap(RtlGetProcessHeap(), 0, OldCurDir);
1932 }
1933
1934 return Status;
1935}
1936
1937/*
1938 * @implemented
1939 */
1940ULONG
1941NTAPI
1946 _Out_opt_ PWSTR *FilePart,
1947 _Out_opt_ RTL_PATH_TYPE *InputPathType)
1948{
1949 UNICODE_STRING FileNameString;
1951
1952 if (InputPathType)
1953 *InputPathType = 0;
1954
1955 /* Build the string */
1956 status = RtlInitUnicodeStringEx(&FileNameString, FileName);
1957 if (!NT_SUCCESS(status)) return 0;
1958
1959 /* Call the extended function */
1961 &FileNameString,
1963 Buffer,
1964 (PCWSTR*)FilePart,
1965 NULL,
1966 InputPathType);
1967}
1968
1969/******************************************************************
1970 * RtlGetFullPathName_U (NTDLL.@)
1971 *
1972 * Returns the number of bytes written to buffer (not including the
1973 * terminating NULL) if the function succeeds, or the required number of bytes
1974 * (including the terminating NULL) if the buffer is too small.
1975 *
1976 * file_part will point to the filename part inside buffer (except if we use
1977 * DOS device name, in which case file_in_buf is NULL)
1978 *
1979 * @implemented
1980 */
1981
1982/*
1983 * @implemented
1984 */
1985ULONG
1986NTAPI
1989 _In_ ULONG Size,
1992{
1994
1995 /* Call the extended function */
1997 Size,
1998 Buffer,
1999 ShortName,
2000 &PathType);
2001}
2002
2003/*
2004 * @implemented
2005 */
2006BOOLEAN
2007NTAPI
2009 OUT PUNICODE_STRING NtName,
2010 OUT PCWSTR *PartName,
2011 OUT PRTL_RELATIVE_NAME_U RelativeName)
2012{
2013 /* Call the internal function */
2015 DosName,
2016 NtName,
2017 PartName,
2018 RelativeName));
2019}
2020
2021/*
2022 * @implemented
2023 */
2025NTAPI
2027 OUT PUNICODE_STRING NtName,
2028 OUT PCWSTR *PartName,
2029 OUT PRTL_RELATIVE_NAME_U RelativeName)
2030{
2031 /* Call the internal function */
2033 DosName,
2034 NtName,
2035 PartName,
2036 RelativeName);
2037}
2038
2039/*
2040 * @implemented
2041 */
2042BOOLEAN
2043NTAPI
2045 OUT PUNICODE_STRING NtName,
2046 OUT PCWSTR *PartName,
2047 OUT PRTL_RELATIVE_NAME_U RelativeName)
2048{
2049 /* Call the internal function */
2050 ASSERT(RelativeName);
2052 DosName,
2053 NtName,
2054 PartName,
2055 RelativeName));
2056}
2057
2058/*
2059 * @implemented
2060 */
2062NTAPI
2064 OUT PUNICODE_STRING NtName,
2065 OUT PCWSTR *PartName,
2066 OUT PRTL_RELATIVE_NAME_U RelativeName)
2067{
2068 /* Call the internal function */
2069 ASSERT(RelativeName);
2071 DosName,
2072 NtName,
2073 PartName,
2074 RelativeName);
2075}
2076
2077/*
2078 * @implemented
2079 */
2084{
2085 PCUNICODE_STRING UsePrefix = NULL, AlternatePrefix = NULL;
2086
2087 if (PathType)
2088 *PathType = 0;
2089
2090 if (!Path || Flags)
2092
2093 /* The initial check is done on Path->String */
2095 {
2096 UsePrefix = &RtlpDosDevicesUncPrefix;
2097 AlternatePrefix = &RtlpDoubleSlashPrefix;
2098 if (PathType)
2100 }
2102 {
2103 UsePrefix = &RtlpDosDevicesPrefix;
2104 if (PathType)
2106 }
2107
2108 if (UsePrefix)
2109 {
2111
2112 USHORT Len = Path->String.Length - UsePrefix->Length;
2113 if (AlternatePrefix)
2114 Len += AlternatePrefix->Length;
2115
2116 Status = RtlEnsureBufferSize(0, &Path->ByteBuffer, Len);
2117 if (!NT_SUCCESS(Status))
2118 return Status;
2119
2120 if (Len + sizeof(UNICODE_NULL) <= Path->ByteBuffer.Size)
2121 {
2122 /* Then, the contents of Path->ByteBuffer are always used... */
2123 if (AlternatePrefix)
2124 {
2125 memcpy(Path->ByteBuffer.Buffer, AlternatePrefix->Buffer, AlternatePrefix->Length);
2126 memmove(Path->ByteBuffer.Buffer + AlternatePrefix->Length, Path->ByteBuffer.Buffer + UsePrefix->Length,
2127 Len - AlternatePrefix->Length);
2128 }
2129 else
2130 {
2132 }
2134 Path->String.Length = Len;
2136 Path->String.Buffer[Len / sizeof(WCHAR)] = UNICODE_NULL;
2137 }
2138 return STATUS_SUCCESS;
2139 }
2140
2141 if (PathType)
2142 {
2144 {
2150 break;
2151 case RtlPathTypeUnknown:
2153 case RtlPathTypeRooted:
2156 break;
2157 }
2158 }
2159
2160 return STATUS_SUCCESS;
2161}
2162
2163/*
2164 * @implemented
2165 */
2166ULONG
2167NTAPI
2171 IN ULONG Size,
2172 IN PWSTR Buffer,
2173 OUT PWSTR *PartName)
2174{
2176 ULONG ExtensionLength, Length, FileNameLength, PathLength;
2177 UNICODE_STRING TempString;
2178 PWCHAR NewBuffer, BufferStart;
2179 PCWSTR p;
2180
2181 /* Check if this is an absolute path */
2183 {
2184 /* Check if the file exists */
2186 {
2187 /* Get the full name, which does the DOS lookup */
2188 return RtlGetFullPathName_U(FileName, Size, Buffer, PartName);
2189 }
2190
2191 /* Doesn't exist, so fail */
2192 return 0;
2193 }
2194
2195 /* Scan the filename */
2196 p = FileName;
2197 while (*p)
2198 {
2199 /* Looking for an extension */
2200 if (*p == L'.')
2201 {
2202 /* No extension string needed -- it's part of the filename */
2203 Extension = NULL;
2204 break;
2205 }
2206
2207 /* Next character */
2208 p++;
2209 }
2210
2211 /* Do we have an extension? */
2212 if (!Extension)
2213 {
2214 /* Nope, don't worry about one */
2215 ExtensionLength = 0;
2216 }
2217 else
2218 {
2219 /* Build a temporary string to get the extension length */
2220 Status = RtlInitUnicodeStringEx(&TempString, Extension);
2221 if (!NT_SUCCESS(Status)) return 0;
2222 ExtensionLength = TempString.Length;
2223 }
2224
2225 /* Build a temporary string to get the path length */
2226 Status = RtlInitUnicodeStringEx(&TempString, Path);
2227 if (!NT_SUCCESS(Status)) return 0;
2228 PathLength = TempString.Length;
2229
2230 /* Build a temporary string to get the filename length */
2231 Status = RtlInitUnicodeStringEx(&TempString, FileName);
2232 if (!NT_SUCCESS(Status)) return 0;
2233 FileNameLength = TempString.Length;
2234
2235 /* Allocate the buffer for the new string name */
2236 NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
2237 0,
2239 ExtensionLength +
2240 PathLength +
2241 3 * sizeof(WCHAR));
2242 if (!NewBuffer)
2243 {
2244 /* Fail the call */
2245 DbgPrint("%s: Failing due to out of memory (RtlAllocateHeap failure)\n",
2246 __FUNCTION__);
2247 return 0;
2248 }
2249
2250 /* Final loop to build the path */
2251 while (TRUE)
2252 {
2253 /* Check if we have a valid character */
2254 BufferStart = NewBuffer;
2255 if (*Path)
2256 {
2257 /* Loop as long as there's no semicolon */
2258 while (*Path != L';')
2259 {
2260 /* Copy the next character */
2261 *BufferStart++ = *Path++;
2262 if (!*Path) break;
2263 }
2264
2265 /* We found a semi-colon, to stop path processing on this loop */
2266 if (*Path == L';') ++Path;
2267 }
2268
2269 /* Add a terminating slash if needed */
2270 if ((BufferStart != NewBuffer) && (BufferStart[-1] != OBJ_NAME_PATH_SEPARATOR))
2271 {
2272 *BufferStart++ = OBJ_NAME_PATH_SEPARATOR;
2273 }
2274
2275 /* Bail out if we reached the end */
2276 if (!*Path) Path = NULL;
2277
2278 /* Copy the file name and check if an extension is needed */
2279 RtlCopyMemory(BufferStart, FileName, FileNameLength);
2280 if (ExtensionLength)
2281 {
2282 /* Copy the extension too */
2283 RtlCopyMemory((PCHAR)BufferStart + FileNameLength,
2284 Extension,
2285 ExtensionLength + sizeof(WCHAR));
2286 }
2287 else
2288 {
2289 /* Just NULL-terminate */
2290 *(PWCHAR)((PCHAR)BufferStart + FileNameLength) = UNICODE_NULL;
2291 }
2292
2293 /* Now, does this file exist? */
2294 if (RtlDoesFileExists_UEx(NewBuffer, FALSE))
2295 {
2296 /* Call the full-path API to get the length */
2297 Length = RtlGetFullPathName_U(NewBuffer, Size, Buffer, PartName);
2298 break;
2299 }
2300
2301 /* If we got here, path doesn't exist, so fail the call */
2302 Length = 0;
2303 if (!Path) break;
2304 }
2305
2306 /* Free the allocation and return the length */
2307 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
2308 return Length;
2309}
2310
2311/*
2312 * @implemented
2313 */
2315NTAPI
2320 IN PSIZE_T FilePartSize,
2324{
2326 PWCHAR StaticBuffer;
2328 ULONG Length;
2329 USHORT StaticLength;
2330 UNICODE_STRING TempDynamicString;
2331
2332 /* Initialize all our locals */
2333 ShortName = NULL;
2334 StaticBuffer = NULL;
2335 TempDynamicString.Buffer = NULL;
2336
2337 /* Initialize the input parameters */
2338 if (StringUsed) *StringUsed = NULL;
2339 if (LengthNeeded) *LengthNeeded = 0;
2340 if (FilePartSize) *FilePartSize = 0;
2341
2342 /* Check for invalid parameters */
2343 if ((DynamicString) && !(StringUsed) && (StaticString))
2344 {
2346 }
2347
2348 /* Check if we did not get an input string */
2349 if (!StaticString)
2350 {
2351 /* Allocate one */
2352 StaticLength = MAX_PATH * sizeof(WCHAR);
2353 StaticBuffer = RtlpAllocateStringMemory(MAX_PATH * sizeof(WCHAR), TAG_USTR);
2354 if (!StaticBuffer) return STATUS_NO_MEMORY;
2355 }
2356 else
2357 {
2358 /* Use the one we received */
2359 StaticBuffer = StaticString->Buffer;
2360 StaticLength = StaticString->MaximumLength;
2361 }
2362
2363 /* Call the lower-level function */
2365 StaticLength,
2366 StaticBuffer,
2367 &ShortName,
2369 PathType);
2370 DPRINT("Length: %u StaticBuffer: %S\n", Length, StaticBuffer);
2371 if (!Length)
2372 {
2373 /* Fail if it failed */
2374 DbgPrint("%s(%d) - RtlGetFullPathName_Ustr() returned 0\n",
2376 __LINE__);
2378 goto Quickie;
2379 }
2380
2381 /* Check if it fits inside our static string */
2382 if ((StaticString) && (Length < StaticLength))
2383 {
2384 /* Set the final length */
2386
2387 /* Set the file part size */
2388 if (FilePartSize) *FilePartSize = ShortName ? (ShortName - StaticString->Buffer) : 0;
2389
2390 /* Return the static string if requested */
2392
2393 /* We are done with success */
2395 goto Quickie;
2396 }
2397
2398 /* Did we not have an input dynamic string ?*/
2399 if (!DynamicString)
2400 {
2401 /* Return the length we need */
2403
2404 /* And fail such that the caller can try again */
2406 goto Quickie;
2407 }
2408
2409 /* Check if it fits in our static buffer */
2410 if ((StaticBuffer) && (Length < StaticLength))
2411 {
2412 /* NULL-terminate it */
2413 StaticBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2414
2415 /* Set the settings for the dynamic string the caller sent */
2416 DynamicString->MaximumLength = StaticLength;
2418 DynamicString->Buffer = StaticBuffer;
2419
2420 /* Set the part size */
2421 if (FilePartSize) *FilePartSize = ShortName ? (ShortName - StaticBuffer) : 0;
2422
2423 /* Return the dynamic string if requested */
2425
2426 /* Do not free the static buffer on exit, and return success */
2427 StaticBuffer = NULL;
2429 goto Quickie;
2430 }
2431
2432 /* Now try again under the PEB lock */
2435 StaticLength,
2436 StaticBuffer,
2437 &ShortName,
2439 PathType);
2440 if (!Length)
2441 {
2442 /* It failed */
2443 DbgPrint("%s line %d: RtlGetFullPathName_Ustr() returned 0\n",
2444 __FUNCTION__, __LINE__);
2446 goto Release;
2447 }
2448
2449 /* Check if it fits inside our static string now */
2450 if ((StaticString) && (Length < StaticLength))
2451 {
2452 /* Set the final length */
2454
2455 /* Set the file part size */
2456 if (FilePartSize) *FilePartSize = ShortName ? (ShortName - StaticString->Buffer) : 0;
2457
2458 /* Return the static string if requested */
2460
2461 /* We are done with success */
2463 goto Release;
2464 }
2465
2466 /* Check if the path won't even fit in a real string */
2467 if ((Length + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES)
2468 {
2469 /* Name is way too long, fail */
2471 goto Release;
2472 }
2473
2474 /* Allocate the string to hold the path name now */
2475 TempDynamicString.Buffer = RtlpAllocateStringMemory(Length + sizeof(WCHAR),
2476 TAG_USTR);
2477 if (!TempDynamicString.Buffer)
2478 {
2479 /* Out of memory, fail */
2481 goto Release;
2482 }
2483
2484 /* Add space for a NULL terminator, and now check the full path */
2485 TempDynamicString.MaximumLength = (USHORT)Length + sizeof(UNICODE_NULL);
2487 Length,
2488 TempDynamicString.Buffer,
2489 &ShortName,
2491 PathType);
2492 if (!Length)
2493 {
2494 /* Some path error, so fail out */
2495 DbgPrint("%s line %d: RtlGetFullPathName_Ustr() returned 0\n",
2496 __FUNCTION__, __LINE__);
2498 goto Release;
2499 }
2500
2501 /* It should fit in the string we just allocated */
2502 ASSERT(Length < (TempDynamicString.MaximumLength - sizeof(WCHAR)));
2503 if (Length > TempDynamicString.MaximumLength)
2504 {
2505 /* This is really weird and would mean some kind of race */
2507 goto Release;
2508 }
2509
2510 /* Return the file part size */
2511 if (FilePartSize) *FilePartSize = ShortName ? (ShortName - TempDynamicString.Buffer) : 0;
2512
2513 /* Terminate the whole string now */
2514 TempDynamicString.Buffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2515
2516 /* Finalize the string and return it to the user */
2517 DynamicString->Buffer = TempDynamicString.Buffer;
2519 DynamicString->MaximumLength = TempDynamicString.MaximumLength;
2521
2522 /* Return success and make sure we don't free the buffer on exit */
2523 TempDynamicString.Buffer = NULL;
2525
2526Release:
2527 /* Release the PEB lock */
2529
2530Quickie:
2531 /* Free any buffers we should be freeing */
2532 DPRINT("Status: %lx %S %S\n", Status, StaticBuffer, TempDynamicString.Buffer);
2533 if ((StaticString) && (StaticBuffer) && (StaticBuffer != StaticString->Buffer))
2534 {
2535 RtlpFreeStringMemory(StaticBuffer, TAG_USTR);
2536 }
2537 if (TempDynamicString.Buffer)
2538 {
2539 RtlpFreeStringMemory(TempDynamicString.Buffer, TAG_USTR);
2540 }
2541
2542 /* Print out any unusual errors */
2543 if ((NT_ERROR(Status)) &&
2545 {
2546 DbgPrint("RTL: %s - failing on filename %wZ with status %08lx\n",
2548 }
2549
2550 /* Return, we're all done */
2551 return Status;
2552}
2553
2554/*
2555 * @implemented
2556 */
2558NTAPI
2560 IN PUNICODE_STRING PathString,
2561 IN PUNICODE_STRING FileNameString,
2562 IN PUNICODE_STRING ExtensionString,
2563 IN PUNICODE_STRING CallerBuffer,
2565 OUT PUNICODE_STRING* FullNameOut OPTIONAL,
2566 OUT PSIZE_T FilePartSize OPTIONAL,
2568{
2569 WCHAR StaticCandidateBuffer[MAX_PATH];
2570 UNICODE_STRING StaticCandidateString;
2573 PWCHAR p, End, CandidateEnd, SegmentEnd;
2574 SIZE_T SegmentSize, ByteCount, PathSize, MaxPathSize = 0;
2575 USHORT NamePlusExtLength, WorstCaseLength, ExtensionLength = 0;
2576 PUNICODE_STRING FullIsolatedPath;
2577 DPRINT("DOS Path Search: %lx %wZ %wZ %wZ %wZ %wZ\n",
2578 Flags, PathString, FileNameString, ExtensionString, CallerBuffer, DynamicString);
2579
2580 /* Initialize the input string */
2581 RtlInitEmptyUnicodeString(&StaticCandidateString,
2582 StaticCandidateBuffer,
2583 sizeof(StaticCandidateBuffer));
2584
2585 /* Initialize optional arguments */
2586 if (FullNameOut ) *FullNameOut = NULL;
2587 if (FilePartSize) *FilePartSize = 0;
2588 if (LengthNeeded) *LengthNeeded = 0;
2589 if (DynamicString)
2590 {
2593 }
2594
2595 /* Check for invalid parameters */
2596 if ((Flags & ~7) ||
2597 !(PathString) ||
2598 !(FileNameString) ||
2599 ((CallerBuffer) && (DynamicString) && !(FullNameOut)))
2600 {
2601 /* Fail */
2602 DbgPrint("%s: Invalid parameters passed\n", __FUNCTION__);
2604 goto Quickie;
2605 }
2606
2607 /* First check what kind of path this is */
2609
2610 /* Check if the caller wants to prevent relative .\ and ..\ paths */
2611 if ((Flags & 2) &&
2613 (FileNameString->Length >= (2 * sizeof(WCHAR))) &&
2614 (FileNameString->Buffer[0] == L'.') &&
2615 ((IS_PATH_SEPARATOR(FileNameString->Buffer[1])) ||
2616 ((FileNameString->Buffer[1] == L'.') &&
2617 ((FileNameString->Length >= (3 * sizeof(WCHAR))) &&
2618 (IS_PATH_SEPARATOR(FileNameString->Buffer[2]))))))
2619 {
2620 /* Yes, and this path is like that, so make it seem unknown */
2622 }
2623
2624 /* Now check relative vs non-relative paths */
2626 {
2627 /* Does the caller want SxS? */
2628 if (Flags & 1)
2629 {
2630 /* Apply the SxS magic */
2631 FullIsolatedPath = NULL;
2633 FileNameString,
2634 ExtensionString,
2635 CallerBuffer,
2637 &FullIsolatedPath,
2638 NULL,
2639 FilePartSize,
2640 LengthNeeded);
2641 if (NT_SUCCESS(Status))
2642 {
2643 /* We found the SxS path, return it */
2644 if (FullNameOut) *FullNameOut = FullIsolatedPath;
2645 goto Quickie;
2646 }
2647 else if (Status != STATUS_SXS_KEY_NOT_FOUND)
2648 {
2649 /* Critical SxS error, fail */
2650 DbgPrint("%s: Failing because call to "
2651 "RtlDosApplyIsolationRedirection_Ustr(%wZ) failed with "
2652 "status 0x%08lx\n",
2654 FileNameString,
2655 Status);
2656 goto Quickie;
2657 }
2658 }
2659
2660 /* No SxS key found, or not requested, check if there's an extension */
2661 if (ExtensionString)
2662 {
2663 /* Save the extension length, and check if there's a file name */
2664 ExtensionLength = ExtensionString->Length;
2665 if (FileNameString->Length)
2666 {
2667 /* Start parsing the file name */
2668 End = &FileNameString->Buffer[FileNameString->Length / sizeof(WCHAR)];
2669 while (End > FileNameString->Buffer)
2670 {
2671 /* If we find a path separator, there's no extension */
2672 if (IS_PATH_SEPARATOR(*--End)) break;
2673
2674 /* Otherwise, did we find an extension dot? */
2675 if (*End == L'.')
2676 {
2677 /* Ignore what the caller sent it, use the filename's */
2678 ExtensionString = NULL;
2679 ExtensionLength = 0;
2680 break;
2681 }
2682 }
2683 }
2684 }
2685
2686 /* Check if we got a path */
2687 if (PathString->Length)
2688 {
2689 /* Start parsing the path name, looking for path separators */
2690 End = &PathString->Buffer[PathString->Length / sizeof(WCHAR)];
2691 p = End;
2692 while ((p > PathString->Buffer) && (*--p == L';'))
2693 {
2694 /* This is the size of the path -- handle a trailing slash */
2695 PathSize = End - p - 1;
2696 if ((PathSize) && !(IS_PATH_SEPARATOR(*(End - 1)))) PathSize++;
2697
2698 /* Check if we found a bigger path than before */
2699 if (PathSize > MaxPathSize) MaxPathSize = PathSize;
2700
2701 /* Keep going with the path after this path separator */
2702 End = p;
2703 }
2704
2705 /* This is the trailing path, run the same code as above */
2706 PathSize = End - p;
2707 if ((PathSize) && !(IS_PATH_SEPARATOR(*(End - 1)))) PathSize++;
2708 if (PathSize > MaxPathSize) MaxPathSize = PathSize;
2709
2710 /* Finally, convert the largest path size into WCHAR */
2711 MaxPathSize *= sizeof(WCHAR);
2712 }
2713
2714 /* Use the extension, the file name, and the largest path as the size */
2715 WorstCaseLength = ExtensionLength +
2716 FileNameString->Length +
2717 (USHORT)MaxPathSize +
2718 sizeof(UNICODE_NULL);
2719 if (WorstCaseLength > UNICODE_STRING_MAX_BYTES)
2720 {
2721 /* It has to fit in a registry string, if not, fail here */
2722 DbgPrint("%s returning STATUS_NAME_TOO_LONG because the computed "
2723 "worst case file name length is %Iu bytes\n",
2725 WorstCaseLength);
2727 goto Quickie;
2728 }
2729
2730 /* Scan the path now, to see if we can find the file */
2731 p = PathString->Buffer;
2732 End = &p[PathString->Length / sizeof(WCHAR)];
2733 while (p < End)
2734 {
2735 /* Find out where this path ends */
2736 for (SegmentEnd = p;
2737 ((SegmentEnd != End) && (*SegmentEnd != L';'));
2738 SegmentEnd++);
2739
2740 /* Compute the size of this path */
2741 ByteCount = SegmentSize = (SegmentEnd - p) * sizeof(WCHAR);
2742
2743 /* Handle trailing slash if there isn't one */
2744 if ((SegmentSize) && !(IS_PATH_SEPARATOR(*(SegmentEnd - 1))))
2745 {
2746 /* Add space for one */
2748 }
2749
2750 /* Now check if our initial static buffer is too small */
2751 if (StaticCandidateString.MaximumLength <
2752 (SegmentSize + ExtensionLength + FileNameString->Length))
2753 {
2754 /* At this point we should've been using our static buffer */
2755 ASSERT(StaticCandidateString.Buffer == StaticCandidateBuffer);
2756 if (StaticCandidateString.Buffer != StaticCandidateBuffer)
2757 {
2758 /* Something is really messed up if this was the dynamic string */
2759 DbgPrint("%s: internal error #1; "
2760 "CandidateString.Buffer = %p; "
2761 "StaticCandidateBuffer = %p\n",
2763 StaticCandidateString.Buffer,
2764 StaticCandidateBuffer);
2766 goto Quickie;
2767 }
2768
2769 /* We checked before that the maximum possible size shoudl fit! */
2770 ASSERT((SegmentSize + FileNameString->Length + ExtensionLength) <
2772 if ((SegmentSize + ExtensionLength + FileNameString->Length) >
2773 (UNICODE_STRING_MAX_BYTES - sizeof(WCHAR)))
2774 {
2775 /* For some reason it's not fitting anymore. Something messed up */
2776 DbgPrint("%s: internal error #2; SegmentSize = %u, "
2777 "FileName->Length = %u, DefaultExtensionLength = %u\n",
2780 FileNameString->Length,
2781 ExtensionLength);
2783 goto Quickie;
2784 }
2785
2786 /* Now allocate the dynamic string */
2787 StaticCandidateString.MaximumLength = FileNameString->Length +
2788 WorstCaseLength;
2789 StaticCandidateString.Buffer = RtlpAllocateStringMemory(WorstCaseLength,
2790 TAG_USTR);
2791 if (!StaticCandidateString.Buffer)
2792 {
2793 /* Out of memory, fail */
2794 DbgPrint("%s: Unable to allocate %u byte buffer for path candidate\n",
2796 StaticCandidateString.MaximumLength);
2798 goto Quickie;
2799 }
2800 }
2801
2802 /* Copy the path in the string */
2803 RtlCopyMemory(StaticCandidateString.Buffer, p, ByteCount);
2804
2805 /* Get to the end of the string, and add the trailing slash if missing */
2806 CandidateEnd = &StaticCandidateString.Buffer[ByteCount / sizeof(WCHAR)];
2807 if ((SegmentSize) && (SegmentSize != ByteCount))
2808 {
2809 *CandidateEnd++ = OBJ_NAME_PATH_SEPARATOR;
2810 }
2811
2812 /* Copy the filename now */
2813 RtlCopyMemory(CandidateEnd,
2814 FileNameString->Buffer,
2815 FileNameString->Length);
2816 CandidateEnd += (FileNameString->Length / sizeof(WCHAR));
2817
2818 /* Check if there was an extension */
2819 if (ExtensionString)
2820 {
2821 /* Copy the extension too */
2822 RtlCopyMemory(CandidateEnd,
2823 ExtensionString->Buffer,
2824 ExtensionString->Length);
2825 CandidateEnd += (ExtensionString->Length / sizeof(WCHAR));
2826 }
2827
2828 /* We are done, terminate it */
2829 *CandidateEnd = UNICODE_NULL;
2830
2831 /* Now set the final length of the string so it becomes valid */
2832 StaticCandidateString.Length = (USHORT)(CandidateEnd -
2833 StaticCandidateString.Buffer) *
2834 sizeof(WCHAR);
2835
2836 /* Check if this file exists */
2837 DPRINT("BUFFER: %S\n", StaticCandidateString.Buffer);
2838 if (RtlDoesFileExists_UEx(StaticCandidateString.Buffer, FALSE))
2839 {
2840 /* Awesome, it does, now get the full path */
2841 Status = RtlGetFullPathName_UstrEx(&StaticCandidateString,
2842 CallerBuffer,
2844 (PUNICODE_STRING*)FullNameOut,
2845 FilePartSize,
2846 NULL,
2847 &PathType,
2848 LengthNeeded);
2849 if (!(NT_SUCCESS(Status)) &&
2852 {
2853 DbgPrint("%s: Failing because we thought we found %wZ on "
2854 "the search path, but RtlGetfullPathNameUStrEx() "
2855 "returned %08lx\n",
2857 &StaticCandidateString,
2858 Status);
2859 }
2860 DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
2861 goto Quickie;
2862 }
2863 else
2864 {
2865 /* Otherwise, move to the next path */
2866 if (SegmentEnd != End)
2867 {
2868 /* Handle the case of the path separator trailing */
2869 p = SegmentEnd + 1;
2870 }
2871 else
2872 {
2873 p = SegmentEnd;
2874 }
2875 }
2876 }
2877
2878 /* Loop finished and we didn't break out -- fail */
2880 }
2881 else
2882 {
2883 /* We have a full path, so check if it does exist */
2884 DPRINT("%wZ\n", FileNameString);
2885 if (!RtlDoesFileExists_UstrEx(FileNameString, TRUE))
2886 {
2887 /* It doesn't exist, did we have an extension? */
2888 if (!(ExtensionString) || !(ExtensionString->Length))
2889 {
2890 /* No extension, so just fail */
2892 goto Quickie;
2893 }
2894
2895 /* There was an extension, check if the filename already had one */
2896 if (!(Flags & 4) && (FileNameString->Length))
2897 {
2898 /* Parse the filename */
2899 p = FileNameString->Buffer;
2900 End = &p[FileNameString->Length / sizeof(WCHAR)];
2901 while (End > p)
2902 {
2903 /* If there's a path separator, there's no extension */
2904 if (IS_PATH_SEPARATOR(*--End)) break;
2905
2906 /* Othwerwise, did we find an extension dot? */
2907 if (*End == L'.')
2908 {
2909 /* File already had an extension, so fail */
2911 goto Quickie;
2912 }
2913 }
2914 }
2915
2916 /* So there is an extension, we'll try again by adding it */
2917 NamePlusExtLength = FileNameString->Length +
2918 ExtensionString->Length +
2919 sizeof(UNICODE_NULL);
2920 if (NamePlusExtLength > UNICODE_STRING_MAX_BYTES)
2921 {
2922 /* It won't fit in any kind of valid string, so fail */
2923 DbgPrint("%s: Failing because filename plus extension (%Iu bytes) is too big\n",
2925 NamePlusExtLength);
2927 goto Quickie;
2928 }
2929
2930 /* Fill it fit in our temporary string? */
2931 if (NamePlusExtLength > StaticCandidateString.MaximumLength)
2932 {
2933 /* It won't fit anymore, allocate a dynamic string for it */
2934 StaticCandidateString.MaximumLength = NamePlusExtLength;
2935 StaticCandidateString.Buffer = RtlpAllocateStringMemory(NamePlusExtLength,
2936 TAG_USTR);
2937 if (!StaticCandidateString.Buffer)
2938 {
2939 /* Ran out of memory, so fail */
2940 DbgPrint("%s: Failing because allocating the dynamic filename buffer failed\n",
2941 __FUNCTION__);
2943 goto Quickie;
2944 }
2945 }
2946
2947 /* Copy the filename */
2948 RtlCopyUnicodeString(&StaticCandidateString, FileNameString);
2949
2950 /* Copy the extension */
2951 RtlAppendUnicodeStringToString(&StaticCandidateString,
2952 ExtensionString);
2953
2954 DPRINT("SB: %wZ\n", &StaticCandidateString);
2955
2956 /* And check if this file now exists */
2957 if (!RtlDoesFileExists_UstrEx(&StaticCandidateString, TRUE))
2958 {
2959 /* Still no joy, fail out */
2961 goto Quickie;
2962 }
2963
2964 /* File was found, get the final full path */
2965 Status = RtlGetFullPathName_UstrEx(&StaticCandidateString,
2966 CallerBuffer,
2968 (PUNICODE_STRING*)FullNameOut,
2969 FilePartSize,
2970 NULL,
2971 &PathType,
2972 LengthNeeded);
2974 {
2975 DbgPrint("%s: Failing on \"%wZ\" because RtlGetfullPathNameUStrEx() "
2976 "failed with status %08lx\n",
2978 &StaticCandidateString,
2979 Status);
2980 }
2981 DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
2982 }
2983 else
2984 {
2985 /* File was found on the first try, get the final full path */
2986 Status = RtlGetFullPathName_UstrEx(FileNameString,
2987 CallerBuffer,
2989 (PUNICODE_STRING*)FullNameOut,
2990 FilePartSize,
2991 NULL,
2992 &PathType,
2993 LengthNeeded);
2994 if (!(NT_SUCCESS(Status)) &&
2997 {
2998 DbgPrint("%s: Failing because RtlGetfullPathNameUStrEx() on %wZ "
2999 "failed with status %08lx\n",
3001 FileNameString,
3002 Status);
3003 }
3004 DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
3005 }
3006 }
3007
3008Quickie:
3009 /* Anything that was not an error, turn into STATUS_SUCCESS */
3011
3012 /* Check if we had a dynamic string */
3013 if ((StaticCandidateString.Buffer) &&
3014 (StaticCandidateString.Buffer != StaticCandidateBuffer))
3015 {
3016 /* Free it */
3017 RtlFreeUnicodeString(&StaticCandidateString);
3018 }
3019
3020 /* Return the status */
3021 return Status;
3022}
3023
3024/*
3025 * @implemented
3026 */
3027BOOLEAN
3028NTAPI
3030{
3031 /* Call the new function */
3033}
3034
3035/* EOF */
#define NtCurrentPeb()
Definition: FLS.c:22
static USHORT PathLength
unsigned char BOOLEAN
static IN BOOLEAN SucceedIfBusy
IN PUNICODE_STRING StaticString
IN PUNICODE_STRING IN PUNICODE_STRING DynamicString
IN PUNICODE_STRING IN PUNICODE_STRING IN PUNICODE_STRING * StringUsed
IN PUNICODE_STRING IN PUNICODE_STRING IN PUNICODE_STRING IN PSIZE_T FilePartSize OUT PBOOLEAN NameInvalid
static IN ULONG IN PWSTR OUT PCWSTR OUT PBOOLEAN OUT PATH_TYPE_AND_UNKNOWN * PathType
static IN ULONG IN PWSTR OUT PCWSTR OUT PBOOLEAN InvalidName
PRTL_UNICODE_STRING_BUFFER Path
Type
Definition: Type.h:7
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
#define FILE_DIRECTORY_FILE
Definition: constants.h:491
#define DPRINT1
Definition: precomp.h:8
WCHAR FileNameBuffer[MAX_PATH]
Definition: framewnd.c:233
WCHAR CurrentDirectory[1024]
Definition: chkdsk.c:74
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:590
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:608
_In_ BOOLEAN Release
Definition: cdrom.h:920
Definition: bufpool.h:45
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define Len
Definition: deflate.h:82
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
NTSYSAPI NTSTATUS NTAPI RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags, IN PUNICODE_STRING OriginalName, IN PUNICODE_STRING Extension, IN OUT PUNICODE_STRING StaticString, IN OUT PUNICODE_STRING DynamicString, IN OUT PUNICODE_STRING *NewName, IN PULONG NewFlags, IN PSIZE_T FileNameSize, IN PSIZE_T RequiredLength)
Definition: libsupp.c:818
#define NTSTATUS
Definition: precomp.h:21
#define wcsrchr
Definition: compat.h:16
#define MAX_PATH
Definition: compat.h:34
#define FILE_SHARE_READ
Definition: compat.h:136
#define __FUNCTION__
Definition: types.h:116
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:43
UNICODE_STRING * PUNICODE_STRING
Definition: env_spec_w32.h:373
IN PDCB IN POEM_STRING IN PUNICODE_STRING IN OUT POEM_STRING ShortName
Definition: fatprocs.h:1306
struct _FileName FileName
Definition: fatprocs.h:896
_Inout_opt_ PUNICODE_STRING Extension
Definition: fltkernel.h:1092
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ HANDLE _In_ ULONG FileNameLength
Definition: fltkernel.h:1129
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ SECURITY_INFORMATION _In_ ULONG _Out_opt_ PULONG LengthNeeded
Definition: fltkernel.h:1343
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
@ FileFsDeviceInformation
Definition: from_kernel.h:222
Status
Definition: gdiplustypes.h:25
const GLubyte * c
Definition: glext.h:8905
GLfloat GLfloat p
Definition: glext.h:8902
#define DbgPrint
Definition: hal.h:12
@ Unknown
Definition: i8042prt.h:114
#define iswdigit(_c)
Definition: ctype.h:667
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define OBJ_INHERIT
Definition: winternl.h:225
NTSYSAPI void WINAPI RtlReleasePebLock(void)
Definition: libsupp.c:82
NTSYSAPI void WINAPI RtlAcquirePebLock(void)
Definition: libsupp.c:72
NTSYSAPI NTSTATUS WINAPI RtlInitUnicodeStringEx(PUNICODE_STRING, PCWSTR)
NTSYSAPI DWORD WINAPI RtlGetLongestNtPathLength(void)
Definition: path.c:1555
NTSYSAPI PEB *WINAPI RtlGetCurrentPeb(void)
Definition: libsupp.c:63
NTSYSAPI NTSTATUS WINAPI RtlDosPathNameToNtPathName_U_WithStatus(PCWSTR, PUNICODE_STRING, PWSTR *, CURDIR *)
#define C_ASSERT(e)
Definition: intsafe.h:73
#define c
Definition: ke_i.h:80
#define PCHAR
Definition: match.c:90
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
_In_ UINT Bytes
Definition: mmcopy.h:9
#define ASSERT(a)
Definition: mode.c:44
static PVOID ptr
Definition: dispmode.c:27
static ULONG_PTR
Definition: path.c:79
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define _Out_opt_
Definition: ms_sal.h:346
#define _Inout_
Definition: ms_sal.h:378
#define _Out_writes_bytes_(size)
Definition: ms_sal.h:350
#define _Out_z_bytecap_(size)
Definition: ms_sal.h:885
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _Out_bytecap_(size)
Definition: ms_sal.h:854
_In_ UINT _In_ UINT _In_ PNDIS_PACKET Source
Definition: ndis.h:3169
NTSYSAPI NTSTATUS NTAPI ZwQueryAttributesFile(_In_ POBJECT_ATTRIBUTES ObjectAttributes, _Out_ PFILE_BASIC_INFORMATION FileInformation)
#define RTL_UNCHANGED_DOS_PATH
Definition: rtlfuncs.h:2974
NTSYSAPI NTSTATUS NTAPI RtlDosSearchPath_Ustr(_In_ ULONG Flags, _In_ PUNICODE_STRING PathString, _In_ PUNICODE_STRING FileNameString, _In_ PUNICODE_STRING ExtensionString, _In_ PUNICODE_STRING CallerBuffer, _Inout_opt_ PUNICODE_STRING DynamicString, _Out_opt_ PUNICODE_STRING *FullNameOut, _Out_opt_ PSIZE_T FilePartSize, _Out_opt_ PSIZE_T LengthNeeded)
#define RTL_CONVERTED_NT_PATH
Definition: rtlfuncs.h:2973
NTSYSAPI RTL_PATH_TYPE NTAPI RtlDetermineDosPathNameType_U(_In_ PCWSTR Path)
#define RTL_CONVERTED_UNC_PATH
Definition: rtlfuncs.h:2972
NTSYSAPI NTSTATUS NTAPI RtlSetCurrentDirectory_U(_In_ PUNICODE_STRING name)
NTSYSAPI ULONG NTAPI RtlGetFullPathName_U(_In_ PCWSTR FileName, _In_ ULONG Size, _Out_z_bytecap_(Size) PWSTR Buffer, _Out_opt_ PWSTR *ShortName)
Definition: path.c:1987
#define RTL_UNCHANGED_UNK_PATH
Definition: rtlfuncs.h:2971
NTSYSAPI NTSTATUS NTAPI RtlQueryEnvironmentVariable_U(_In_opt_ PWSTR Environment, _In_ PCUNICODE_STRING Name, _Out_ PUNICODE_STRING Value)
NTSYSAPI ULONG NTAPI RtlGetCurrentDirectory_U(_In_ ULONG MaximumLength, _Out_bytecap_(MaximumLength) PWSTR Buffer)
Definition: path.c:1661
struct _RTL_UNICODE_STRING_BUFFER * PRTL_UNICODE_STRING_BUFFER
@ RtlPathTypeRootLocalDevice
Definition: rtltypes.h:478
@ RtlPathTypeDriveRelative
Definition: rtltypes.h:474
@ RtlPathTypeRelative
Definition: rtltypes.h:476
@ RtlPathTypeUncAbsolute
Definition: rtltypes.h:472
@ RtlPathTypeRooted
Definition: rtltypes.h:475
@ RtlPathTypeLocalDevice
Definition: rtltypes.h:477
@ RtlPathTypeDriveAbsolute
Definition: rtltypes.h:473
@ RtlPathTypeUnknown
Definition: rtltypes.h:471
#define RTL_USER_PROCESS_PARAMETERS_NORMALIZED
Definition: rtltypes.h:41
enum _RTL_PATH_TYPE RTL_PATH_TYPE
WCHAR NTAPI RtlpUpcaseUnicodeChar(_In_ WCHAR Source)
Definition: nlsboot.c:160
WCHAR NTAPI RtlpDowncaseUnicodeChar(_In_ WCHAR Source)
Definition: nlsboot.c:32
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3952
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define SYNCHRONIZE
Definition: nt_native.h:61
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
#define FILE_TRAVERSE
Definition: nt_native.h:643
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
CONST WCHAR * PCWCH
Definition: ntbasedef.h:411
#define UNICODE_NULL
#define UNICODE_STRING_MAX_CHARS
#define UNICODE_STRING_MAX_BYTES
#define ANSI_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define OBJ_HANDLE_TAGBITS
#define RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
Definition: rtl.h:25
NTSTATUS NTAPI RtlFindCharInUnicodeString(_In_ ULONG Flags, _In_ PCUNICODE_STRING SearchString, _In_ PCUNICODE_STRING MatchString, _Out_ PUSHORT Position)
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
#define STATUS_SXS_KEY_NOT_FOUND
Definition: ntstatus.h:1389
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:498
#define L(x)
Definition: ntvdm.h:50
#define LOWORD(l)
Definition: pedump.c:82
unsigned short USHORT
Definition: pedump.c:61
static unsigned __int64 next
Definition: rand_nt.c:6
#define RtlpFreeStringMemory
Definition: rtlp.h:156
#define RtlpAllocateStringMemory
Definition: rtlp.h:155
ULONG NTAPI RtlIsDosDeviceName_U(IN PCWSTR Path)
Definition: path.c:1639
NTSTATUS NTAPI RtlpDosPathNameToRelativeNtPathName_Ustr(IN BOOLEAN HaveRelative, IN PCUNICODE_STRING DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1155
BOOLEAN NTAPI RtlDoesFileExists_UStr(IN PUNICODE_STRING FileName)
Definition: path.c:1503
NTSTATUS NTAPI RtlpWin32NTNameToNtPathName_U(IN PUNICODE_STRING DosPath, OUT PUNICODE_STRING NtPath, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1081
const UNICODE_STRING DeviceRootString
Definition: path.c:34
PRTLP_CURDIR_REF RtlpCurDirRef
Definition: path.c:55
const UNICODE_STRING RtlpDosNULDevice
Definition: path.c:46
const UNICODE_STRING RtlpDosSlashCONDevice
Definition: path.c:38
ULONG NTAPI RtlIsDosDeviceName_Ustr(IN PCUNICODE_STRING PathString)
Definition: path.c:94
static ULONG RtlpCollapsePath(PWSTR Path, ULONG mark, BOOLEAN SkipTrailingPathSeparators)
Definition: path.c:306
const UNICODE_STRING RtlpDosCONDevice
Definition: path.c:45
ULONG NTAPI RtlDosSearchPath_U(IN PCWSTR Path, IN PCWSTR FileName, IN PCWSTR Extension, IN ULONG Size, IN PWSTR Buffer, OUT PWSTR *PartName)
Definition: path.c:2168
static SIZE_T RtlpSkipUNCPrefix(PCWSTR FileNameBuffer)
Definition: path.c:431
#define RTL_CURDIR_DROP_OLD_HANDLE
Definition: path.c:27
static const UNICODE_STRING RtlpDotLocal
Definition: path.c:51
const UNICODE_STRING RtlpDosPRNDevice
Definition: path.c:43
ULONG NTAPI RtlGetFullPathName_UEx(_In_ PWSTR FileName, _In_ ULONG BufferLength, _Out_writes_bytes_(BufferLength) PWSTR Buffer, _Out_opt_ PWSTR *FilePart, _Out_opt_ RTL_PATH_TYPE *InputPathType)
Definition: path.c:1942
const UNICODE_STRING RtlpDosCOMDevice
Definition: path.c:42
static const UNICODE_STRING RtlpPathDividers
Definition: path.c:52
BOOLEAN NTAPI RtlDoesFileExists_U(IN PCWSTR FileName)
Definition: path.c:3029
RTL_PATH_TYPE NTAPI RtlDetermineDosPathNameType_Ustr(IN PCUNICODE_STRING PathString)
Definition: path.c:61
BOOLEAN NTAPI RtlDosPathNameToRelativeNtPathName_Ustr(IN PCUNICODE_STRING DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1414
const UNICODE_STRING RtlpDosDevicesUncPrefix
Definition: path.c:36
BOOLEAN NTAPI RtlDoesFileExists_UstrEx(IN PCUNICODE_STRING FileName, IN BOOLEAN SucceedIfBusy)
Definition: path.c:1430
NTSTATUS NTAPI RtlGetLengthWithoutTrailingPathSeparators(IN ULONG Flags, IN PCUNICODE_STRING PathString, OUT PULONG Length)
Definition: path.c:1573
ULONG NTAPI 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)
Definition: path.c:734
NTSTATUS NTAPI RtlComputePrivatizedDllName_U(_In_ PUNICODE_STRING DllName, _Inout_ PUNICODE_STRING RealName, _Inout_ PUNICODE_STRING LocalName)
Definition: path.c:586
#define RTL_CURDIR_IS_REMOVABLE
Definition: path.c:26
BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:2008
NTSTATUS NTAPI RtlGetLengthWithoutLastFullDosOrNtPathElement(IN ULONG Flags, IN PCUNICODE_STRING Path, OUT PULONG LengthOut)
Definition: path.c:496
const UNICODE_STRING RtlpDosLPTDevice
Definition: path.c:41
const UNICODE_STRING RtlpDosDevicesPrefix
Definition: path.c:39
NTSTATUS NTAPI RtlpDosPathNameToRelativeNtPathName_U(IN BOOLEAN HaveRelative, IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1387
NTSTATUS NTAPI RtlDosPathNameToRelativeNtPathName_U_WithStatus(IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:2063
NTSTATUS NTAPI RtlGetFullPathName_UstrEx(IN PUNICODE_STRING FileName, IN PUNICODE_STRING StaticString, IN PUNICODE_STRING DynamicString, IN PUNICODE_STRING *StringUsed, IN PSIZE_T FilePartSize, OUT PBOOLEAN NameInvalid, OUT RTL_PATH_TYPE *PathType, OUT PSIZE_T LengthNeeded)
Definition: path.c:2316
NTSTATUS NTAPI RtlNtPathNameToDosPathName(IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER Path, OUT PULONG PathType, PULONG Unknown)
Definition: path.c:2080
#define IS_PATH_SEPARATOR(x)
Definition: path.c:24
const UNICODE_STRING RtlpWin32NtRootSlash
Definition: path.c:37
NTSTATUS NTAPI RtlpCheckDeviceName(IN PUNICODE_STRING FileName, IN ULONG Length, OUT PBOOLEAN NameInvalid)
Definition: path.c:255
const UNICODE_STRING RtlpDoubleSlashPrefix
Definition: path.c:48
const UNICODE_STRING RtlpDosAUXDevice
Definition: path.c:44
VOID NTAPI RtlReleaseRelativeName(IN PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1534
BOOLEAN NTAPI RtlDosPathNameToRelativeNtPathName_U(IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:2044
BOOLEAN NTAPI RtlDoesFileExists_UEx(IN PCWSTR FileName, IN BOOLEAN SucceedIfBusy)
Definition: path.c:1511
#define RTL_CURDIR_ALL_FLAGS
Definition: path.c:28
static const UNICODE_STRING RtlpDefaultExtension
Definition: path.c:50
NTSTATUS NTAPI RtlpApplyLengthFunction(IN ULONG Flags, IN ULONG Type, IN PVOID UnicodeStringOrUnicodeStringBuffer, IN NTSTATUS(NTAPI *LengthFunction)(ULONG, PUNICODE_STRING, PULONG))
Definition: path.c:446
NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass)
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define DPRINT
Definition: sndvol32.h:71
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
UNICODE_STRING DosPath
Definition: rtltypes.h:1368
HANDLE Handle
Definition: rtltypes.h:1369
PRTL_USER_PROCESS_PARAMETERS ProcessParameters
Definition: btrfs_drv.h:1913
PUCHAR Buffer
Definition: rtltypes.h:1875
SIZE_T Size
Definition: rtltypes.h:1877
UNICODE_STRING RelativeName
Definition: rtltypes.h:1380
HANDLE ContainingDirectory
Definition: rtltypes.h:1381
UNICODE_STRING String
Definition: rtltypes.h:1885
UNICODE_STRING ImagePathName
Definition: btrfs_drv.h:1901
USHORT MaximumLength
Definition: env_spec_w32.h:370
Definition: ps.c:97
static COORD Position
Definition: mouse.c:34
#define max(a, b)
Definition: svc.c:63
#define TAG_USTR
Definition: tag.h:145
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
ULONG_PTR * PSIZE_T
Definition: typedefs.h:80
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
const uint16_t * PCWSTR
Definition: typedefs.h:57
unsigned char * PBOOLEAN
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
PVOID HANDLE
Definition: typedefs.h:73
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
#define MAKELONG(a, b)
Definition: typedefs.h:249
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
uint16_t * PWCHAR
Definition: typedefs.h:56
uint32_t ULONG
Definition: typedefs.h:59
#define HIWORD(l)
Definition: typedefs.h:247
#define OUT
Definition: typedefs.h:40
char * PCHAR
Definition: typedefs.h:51
#define STATUS_NOT_A_DIRECTORY
Definition: udferr_usr.h:169
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_NO_SUCH_FILE
Definition: udferr_usr.h:137
#define STATUS_SHARING_VIOLATION
Definition: udferr_usr.h:154
#define STATUS_OBJECT_NAME_INVALID
Definition: udferr_usr.h:148
#define NT_ERROR(Status)
Definition: umtypes.h:106
@ Start
Definition: partlist.h:33
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ ULONG _Out_ PVOID _Out_ PULONG RequiredSize
Definition: wdfdevice.h:4439
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3771
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFSTRING String
Definition: wdfdevice.h:2433
_In_ WDFDMATRANSACTION _In_ size_t MaximumLength
BOOL WINAPI EndPath(_In_ HDC)
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_Inout_ PVOID _In_ ULONG SegmentSize
Definition: exfuncs.h:1102
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1099
_Out_ PUNICODE_STRING DosName
Definition: rtlfuncs.h:1269
_In_ __drv_aliasesMem PSTRING Prefix
Definition: rtlfuncs.h:1630
__wchar_t WCHAR
Definition: xmlstorage.h:180