ReactOS  0.4.15-dev-2765-g10e48fa
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 
60 NTAPI
62 {
63  PWCHAR Path;
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 
92 ULONG
93 NTAPI
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 */
109  case RtlPathTypeUnknown:
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++;
173  c = RtlpDowncaseUnicodeChar(*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) &&
239  ((RtlEqualUnicodeString(&PathCopy, &RtlpDosPRNDevice, TRUE)) ||
240  (RtlEqualUnicodeString(&PathCopy, &RtlpDosAUXDevice, TRUE)) ||
241  (RtlEqualUnicodeString(&PathCopy, &RtlpDosNULDevice, TRUE)) ||
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 
253 NTSTATUS
254 NTAPI
256  IN ULONG Length,
258 {
259  PWCHAR Buffer;
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 */
285  *NameInvalid = FALSE;
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  */
305 static ULONG
306 RtlpCollapsePath(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);
314  PWSTR EndPath;
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  }
328  *next = UNICODE_NULL;
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  */
430 static 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 
444 NTSTATUS
445 NTAPI
447  IN ULONG Type,
448  IN PVOID UnicodeStringOrUnicodeStringBuffer,
449  IN NTSTATUS(NTAPI* LengthFunction)(ULONG, PUNICODE_STRING, PULONG))
450 {
453  ULONG Length;
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 
482  return STATUS_NAME_TOO_LONG;
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 
494 NTSTATUS
495 NTAPI
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;
532  case RtlPathTypeRooted:
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 
584 NTSTATUS
585 NTAPI
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 */
643  return STATUS_NAME_TOO_LONG;
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 
732 ULONG
733 NTAPI
736  _In_ ULONG Size,
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;
759  PWCHAR Source;
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);
766  if (InvalidName) *InvalidName = FALSE;
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 */
799  DosLength = RtlIsDosDeviceName_Ustr(FileName);
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  {
866  PrefixCut = RtlpSkipUNCPrefix(FileNameBuffer);
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]);
899  NewDrive = RtlpUpcaseUnicodeChar(FileNameBuffer[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 
1072 Quit:
1073  /* Release PEB lock */
1075 
1076  return reqsize;
1077 }
1078 
1079 NTSTATUS
1080 NTAPI
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 
1153 NTSTATUS
1154 NTAPI
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;
1167  NTSTATUS Status;
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 */
1177  if (!DosName) return STATUS_OBJECT_NAME_INVALID;
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:
1270  case RtlPathTypeRelative:
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 
1385 NTSTATUS
1386 NTAPI
1388  IN PCWSTR DosName,
1389  OUT PUNICODE_STRING NtName,
1390  OUT PCWSTR *PartName,
1391  OUT PRTL_RELATIVE_NAME_U RelativeName)
1392 {
1393  NTSTATUS Status;
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 
1412 BOOLEAN
1413 NTAPI
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 
1428 BOOLEAN
1429 NTAPI
1432 {
1433  BOOLEAN Result;
1434  RTL_RELATIVE_NAME_U RelativeName;
1435  UNICODE_STRING NtPathName;
1436  PVOID Buffer;
1438  NTSTATUS Status;
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 */
1479  if ((Status == STATUS_SHARING_VIOLATION) ||
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 
1501 BOOLEAN
1502 NTAPI
1504 {
1505  /* Call the updated API */
1507 }
1508 
1509 BOOLEAN
1510 NTAPI
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  */
1532 VOID
1533 NTAPI
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  */
1553 ULONG
1554 NTAPI
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  */
1571 NTSTATUS
1572 NTAPI
1574  IN PCUNICODE_STRING PathString,
1575  OUT PULONG Length)
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  */
1612 NTAPI
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  */
1637 ULONG
1638 NTAPI
1640 {
1641  UNICODE_STRING PathString;
1642  NTSTATUS Status;
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  */
1659 ULONG
1660 NTAPI
1664 {
1665  ULONG Length, Bytes;
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  */
1737 NTSTATUS
1738 NTAPI
1740 {
1741  PCURDIR CurDir;
1742  NTSTATUS Status;
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  {
1760  return STATUS_NOT_A_DIRECTORY;
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,
1823  &IoStatusBlock,
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,
1840  &IoStatusBlock,
1843  if (!NT_SUCCESS(Status)) goto Leave;
1844 
1845  /* Get device information */
1846  Status = NtQueryVolumeInformationFile(CurDirHandle,
1847  &IoStatusBlock,
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) */
1895  RtlpCurDirRef->RefCount = 1;
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 
1909 Leave:
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  */
1940 ULONG
1941 NTAPI
1946  _Out_opt_ PWSTR *FilePart,
1947  _Out_opt_ RTL_PATH_TYPE *InputPathType)
1948 {
1949  UNICODE_STRING FileNameString;
1950  NTSTATUS status;
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 */
1960  return RtlGetFullPathName_Ustr(
1961  &FileNameString,
1962  BufferLength,
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  */
1985 ULONG
1986 NTAPI
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  */
2006 BOOLEAN
2007 NTAPI
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  */
2024 NTSTATUS
2025 NTAPI
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  */
2042 BOOLEAN
2043 NTAPI
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  */
2061 NTSTATUS
2062 NTAPI
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  */
2083  PULONG Unknown)
2084 {
2085  PCUNICODE_STRING UsePrefix = NULL, AlternatePrefix = NULL;
2086 
2087  if (PathType)
2088  *PathType = 0;
2089 
2090  if (!Path || Flags)
2091  return STATUS_INVALID_PARAMETER;
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  {
2110  NTSTATUS Status;
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:
2154  case RtlPathTypeRelative:
2156  break;
2157  }
2158  }
2159 
2160  return STATUS_SUCCESS;
2161 }
2162 
2163 /*
2164  * @implemented
2165  */
2166 ULONG
2167 NTAPI
2169  IN PCWSTR FileName,
2171  IN ULONG Size,
2172  IN PWSTR Buffer,
2173  OUT PWSTR *PartName)
2174 {
2175  NTSTATUS Status;
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,
2238  FileNameLength +
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  */
2314 NTSTATUS
2315 NTAPI
2320  IN PSIZE_T FilePartSize,
2324 {
2325  NTSTATUS Status;
2326  PWCHAR StaticBuffer;
2327  PCWCH ShortName;
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  {
2345  return STATUS_INVALID_PARAMETER;
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,
2368  NameInvalid,
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",
2375  __FUNCTION__,
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,
2438  NameInvalid,
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,
2490  NameInvalid,
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 
2526 Release:
2527  /* Release the PEB lock */
2529 
2530 Quickie:
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  RtlpFreeMemory(StaticBuffer, TAG_USTR);
2536  }
2537  if (TempDynamicString.Buffer)
2538  {
2539  RtlpFreeMemory(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  */
2557 NTSTATUS
2558 NTAPI
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;
2571  NTSTATUS Status;
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 */
2608  PathType = RtlDetermineDosPathNameType_Ustr(FileNameString);
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,
2636  DynamicString,
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",
2653  __FUNCTION__,
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",
2724  __FUNCTION__,
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",
2762  __FUNCTION__,
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",
2778  __FUNCTION__,
2779  SegmentSize,
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",
2795  __FUNCTION__,
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,
2843  DynamicString,
2844  (PUNICODE_STRING*)FullNameOut,
2845  FilePartSize,
2846  NULL,
2847  &PathType,
2848  LengthNeeded);
2849  if (!(NT_SUCCESS(Status)) &&
2850  ((Status != STATUS_NO_SUCH_FILE) &&
2852  {
2853  DbgPrint("%s: Failing because we thought we found %wZ on "
2854  "the search path, but RtlGetfullPathNameUStrEx() "
2855  "returned %08lx\n",
2856  __FUNCTION__,
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",
2924  __FUNCTION__,
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,
2967  DynamicString,
2968  (PUNICODE_STRING*)FullNameOut,
2969  FilePartSize,
2970  NULL,
2971  &PathType,
2972  LengthNeeded);
2973  if (!(NT_SUCCESS(Status)) && (Status != STATUS_NO_SUCH_FILE))
2974  {
2975  DbgPrint("%s: Failing on \"%wZ\" because RtlGetfullPathNameUStrEx() "
2976  "failed with status %08lx\n",
2977  __FUNCTION__,
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,
2988  DynamicString,
2989  (PUNICODE_STRING*)FullNameOut,
2990  FilePartSize,
2991  NULL,
2992  &PathType,
2993  LengthNeeded);
2994  if (!(NT_SUCCESS(Status)) &&
2995  ((Status != STATUS_NO_SUCH_FILE) &&
2997  {
2998  DbgPrint("%s: Failing because RtlGetfullPathNameUStrEx() on %wZ "
2999  "failed with status %08lx\n",
3000  __FUNCTION__,
3001  FileNameString,
3002  Status);
3003  }
3004  DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
3005  }
3006  }
3007 
3008 Quickie:
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  */
3027 BOOLEAN
3028 NTAPI
3030 {
3031  /* Call the new function */
3033 }
3034 
3035 /* EOF */
#define RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END
Definition: rtl.h:25
IN PDCB IN POEM_STRING IN PUNICODE_STRING IN OUT POEM_STRING ShortName
Definition: fatprocs.h:1303
RTL_PATH_TYPE NTAPI RtlDetermineDosPathNameType_Ustr(IN PCUNICODE_STRING PathString)
Definition: path.c:61
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
signed char * PCHAR
Definition: retypes.h:7
static IN ULONG IN PWSTR OUT PCWSTR OUT PBOOLEAN InvalidName
#define _Out_z_bytecap_(size)
Definition: sal.h:885
CONST WCHAR * PCWCH
Definition: ntbasedef.h:411
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
enum _RTL_PATH_TYPE RTL_PATH_TYPE
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
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
static const UNICODE_STRING RtlpDotLocal
Definition: path.c:51
ULONG NTAPI RtlIsDosDeviceName_Ustr(IN PCUNICODE_STRING PathString)
Definition: path.c:94
NTSTATUS NTAPI RtlNtPathNameToDosPathName(IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER Path, OUT PULONG PathType, PULONG Unknown)
Definition: path.c:2080
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define IN
Definition: typedefs.h:39
ULONG NTAPI RtlGetLongestNtPathLength(VOID)
Definition: path.c:1555
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3767
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define max(a, b)
Definition: svc.c:63
_In_ __drv_aliasesMem PSTRING Prefix
Definition: rtlfuncs.h:1631
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
static ULONG_PTR *static HANDLE(WINAPI *pCreateActCtxW)(PCACTCTXW)
#define _Out_bytecap_(size)
Definition: sal.h:854
NTSYSAPI NTSTATUS WINAPI RtlInitUnicodeStringEx(PUNICODE_STRING, PCWSTR)
const UNICODE_STRING RtlpDosCONDevice
Definition: path.c:45
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define DbgPrint
Definition: loader.c:25
SIZE_T Size
Definition: rtltypes.h:1873
USHORT MaximumLength
Definition: env_spec_w32.h:370
VOID NTAPI RtlReleaseRelativeName(IN PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1534
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
WCHAR CurrentDirectory[1024]
Definition: chkdsk.c:74
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
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
const UNICODE_STRING RtlpDosAUXDevice
Definition: path.c:44
#define TRUE
Definition: types.h:120
BOOLEAN NTAPI RtlDosPathNameToRelativeNtPathName_U(IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:2044
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
C_ASSERT(RTL_CURDIR_ALL_FLAGS==OBJ_HANDLE_TAGBITS)
uint16_t * PWSTR
Definition: typedefs.h:56
#define FILE_DIRECTORY_FILE
Definition: constants.h:491
static COORD Position
Definition: mouse.c:34
#define iswdigit(_c)
Definition: ctype.h:667
HANDLE ContainingDirectory
Definition: rtltypes.h:1379
#define RTL_UNCHANGED_DOS_PATH
Definition: rtlfuncs.h:2921
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:606
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 RtlpDosSlashCONDevice
Definition: path.c:38
_In_ UINT Bytes
Definition: mmcopy.h:9
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:361
VOID NTAPI RtlReleasePebLock(VOID)
Definition: libsupp.c:82
#define RtlpAllocateStringMemory
Definition: rtlp.h:140
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
#define STATUS_SXS_KEY_NOT_FOUND
Definition: ntstatus.h:1389
VOID NTAPI RtlpFreeMemory(_In_ PVOID Mem, _In_ ULONG Tag)
Definition: rtlcompat.c:45
uint16_t * PWCHAR
Definition: typedefs.h:56
PRTL_USER_PROCESS_PARAMETERS ProcessParameters
Definition: btrfs_drv.h:1959
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
struct _RTL_UNICODE_STRING_BUFFER * PRTL_UNICODE_STRING_BUFFER
static USHORT PathLength
#define UNICODE_STRING_MAX_BYTES
#define IS_PATH_SEPARATOR(x)
Definition: path.c:24
NTSTATUS NTAPI RtlpApplyLengthFunction(IN ULONG Flags, IN ULONG Type, IN PVOID UnicodeStringOrUnicodeStringBuffer, IN NTSTATUS(NTAPI *LengthFunction)(ULONG, PUNICODE_STRING, PULONG))
Definition: path.c:446
#define FILE_SHARE_READ
Definition: compat.h:136
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
const UNICODE_STRING RtlpDosNULDevice
Definition: path.c:46
NTSTATUS NTAPI RtlDosPathNameToNtPathName_U_WithStatus(IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:2026
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
static const UNICODE_STRING RtlpDefaultExtension
Definition: path.c:50
uint32_t ULONG_PTR
Definition: typedefs.h:65
NTSTATUS NTAPI RtlFindCharInUnicodeString(_In_ ULONG Flags, _In_ PCUNICODE_STRING SearchString, _In_ PCUNICODE_STRING MatchString, _Out_ PUSHORT Position)
#define RTL_CONVERTED_UNC_PATH
Definition: rtlfuncs.h:2919
static ULONG_PTR
Definition: path.c:79
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
static IN ULONG IN PWSTR OUT PCWSTR OUT PBOOLEAN OUT PATH_TYPE_AND_UNKNOWN * PathType
#define _Out_writes_bytes_(s)
Definition: no_sal2.h:178
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 FILE_TRAVERSE
Definition: nt_native.h:643
const UNICODE_STRING RtlpDosCOMDevice
Definition: path.c:42
static SIZE_T RtlpSkipUNCPrefix(PCWSTR FileNameBuffer)
Definition: path.c:431
#define STATUS_NOT_A_DIRECTORY
Definition: udferr_usr.h:169
ULONG_PTR * PSIZE_T
Definition: typedefs.h:80
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFSTRING String
Definition: wdfdevice.h:2430
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define STATUS_SHARING_VIOLATION
Definition: udferr_usr.h:154
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
#define ANSI_NULL
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
const UNICODE_STRING RtlpDosLPTDevice
Definition: path.c:41
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
static PVOID ptr
Definition: dispmode.c:27
#define MAKELONG(a, b)
Definition: typedefs.h:249
unsigned char BOOLEAN
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
NTSYSAPI NTSTATUS NTAPI RtlQueryEnvironmentVariable_U(_In_opt_ PWSTR Environment, _In_ PCUNICODE_STRING Name, _Out_ PUNICODE_STRING Value)
_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:426
#define _Out_
Definition: no_sal2.h:160
Definition: bufpool.h:45
static NTSTATUS(WINAPI *pRtlMultiByteToUnicodeN)(LPWSTR dst
BOOLEAN NTAPI RtlDoesFileExists_U(IN PCWSTR FileName)
Definition: path.c:3029
NTSTATUS NTAPI RtlComputePrivatizedDllName_U(_In_ PUNICODE_STRING DllName, _Inout_ PUNICODE_STRING RealName, _Inout_ PUNICODE_STRING LocalName)
Definition: path.c:586
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:498
#define PCHAR
Definition: match.c:90
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
Status
Definition: gdiplustypes.h:24
#define _Out_opt_
Definition: no_sal2.h:214
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:3951
#define OBJ_HANDLE_TAGBITS
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define UNICODE_STRING_MAX_CHARS
_In_ WDFDMATRANSACTION _In_ size_t MaximumLength
#define ASSERT(a)
Definition: mode.c:44
NTSTATUS NTAPI RtlSetCurrentDirectory_U(IN PUNICODE_STRING Path)
Definition: path.c:1739
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static ULONG RtlpCollapsePath(PWSTR Path, ULONG mark, BOOLEAN SkipTrailingPathSeparators)
Definition: path.c:306
#define OBJ_INHERIT
Definition: winternl.h:225
static const UNICODE_STRING RtlpPathDividers
Definition: path.c:52
#define MAX_PATH
Definition: compat.h:34
const GLubyte * c
Definition: glext.h:8905
Type
Definition: Type.h:6
#define Len
Definition: deflate.h:82
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
BOOLEAN NTAPI RtlDoesFileExists_UStr(IN PUNICODE_STRING FileName)
Definition: path.c:1503
PPEB NTAPI RtlGetCurrentPeb(VOID)
Definition: libsupp.c:63
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define _Inout_
Definition: no_sal2.h:162
#define NT_ERROR(Status)
Definition: umtypes.h:106
Definition: partlist.h:33
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3398
ULONG NTAPI RtlGetCurrentDirectory_U(_In_ ULONG MaximumLength, _Out_bytecap_(MaximumLength) PWSTR Buffer)
Definition: path.c:1661
#define RtlpFreeStringMemory
Definition: rtlp.h:141
char * PBOOLEAN
Definition: retypes.h:11
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
#define RTL_CONVERTED_NT_PATH
Definition: rtlfuncs.h:2920
UNICODE_STRING ImagePathName
Definition: btrfs_drv.h:1947
static const WCHAR L[]
Definition: oid.c:1250
BOOLEAN NTAPI RtlDoesFileExists_UEx(IN PCWSTR FileName, IN BOOLEAN SucceedIfBusy)
Definition: path.c:1511
#define InterlockedDecrement
Definition: armddk.h:52
UNICODE_STRING String
Definition: rtltypes.h:1881
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:821
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static IN BOOLEAN SucceedIfBusy
const UNICODE_STRING RtlpDosDevicesPrefix
Definition: path.c:39
_Inout_ PVOID _In_ ULONG SegmentSize
Definition: exfuncs.h:1101
RTL_PATH_TYPE NTAPI RtlDetermineDosPathNameType_U(IN PCWSTR Path)
Definition: path.c:1613
#define wcsrchr
Definition: compat.h:16
#define SYNCHRONIZE
Definition: nt_native.h:61
#define RTL_CURDIR_ALL_FLAGS
Definition: path.c:28
#define TAG_USTR
Definition: libsupp.c:118
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ HANDLE _In_ ULONG FileNameLength
Definition: fltkernel.h:1129
BOOL WINAPI EndPath(HDC hdc)
Definition: path.c:56
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1098
#define _In_
Definition: no_sal2.h:158
ULONG_PTR SIZE_T
Definition: typedefs.h:80
BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:2008
struct _FileName FileName
Definition: fatprocs.h:893
NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass)
_In_ BOOLEAN Release
Definition: cdrom.h:920
PRTL_UNICODE_STRING_BUFFER Path
static unsigned __int64 next
Definition: rand_nt.c:6
IN PUNICODE_STRING IN PUNICODE_STRING IN PUNICODE_STRING IN PSIZE_T FilePartSize OUT PBOOLEAN NameInvalid
#define InterlockedIncrement
Definition: armddk.h:53
#define NtCurrentPeb()
Definition: FLS.c:22
unsigned short USHORT
Definition: pedump.c:61
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
#define STATUS_NO_SUCH_FILE
Definition: udferr_usr.h:137
BOOLEAN NTAPI RtlDoesFileExists_UstrEx(IN PCUNICODE_STRING FileName, IN BOOLEAN SucceedIfBusy)
Definition: path.c:1430
_Out_ PUNICODE_STRING DosName
Definition: rtlfuncs.h:1270
#define STATUS_OBJECT_NAME_INVALID
Definition: udferr_usr.h:148
#define RTL_CURDIR_DROP_OLD_HANDLE
Definition: path.c:27
#define RTL_UNCHANGED_UNK_PATH
Definition: rtlfuncs.h:2918
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
NTSTATUS NTAPI RtlpCheckDeviceName(IN PUNICODE_STRING FileName, IN ULONG Length, OUT PBOOLEAN NameInvalid)
Definition: path.c:255
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
const UNICODE_STRING RtlpDosPRNDevice
Definition: path.c:43
const UNICODE_STRING RtlpWin32NtRootSlash
Definition: path.c:37
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
WCHAR NTAPI RtlpUpcaseUnicodeChar(IN WCHAR Source)
Definition: nls.c:693
UNICODE_STRING * PUNICODE_STRING
Definition: env_spec_w32.h:373
VOID NTAPI RtlAcquirePebLock(VOID)
Definition: libsupp.c:72
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define RTL_CURDIR_IS_REMOVABLE
Definition: path.c:26
#define DPRINT1
Definition: precomp.h:8
UNICODE_STRING DosPath
Definition: rtltypes.h:1366
HANDLE Handle
Definition: rtltypes.h:1367
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
WCHAR FileNameBuffer[_MAX_PATH]
Definition: framewnd.c:240
#define OUT
Definition: typedefs.h:40
PUCHAR Buffer
Definition: rtltypes.h:1871
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
NTSYSAPI NTSTATUS NTAPI ZwQueryAttributesFile(_In_ POBJECT_ATTRIBUTES ObjectAttributes, _Out_ PFILE_BASIC_INFORMATION FileInformation)
#define c
Definition: ke_i.h:80
#define HIWORD(l)
Definition: typedefs.h:247
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
PRTLP_CURDIR_REF RtlpCurDirRef
Definition: path.c:55
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ SECURITY_INFORMATION _In_ ULONG _Out_opt_ PULONG LengthNeeded
Definition: fltkernel.h:1342
UNICODE_STRING RelativeName
Definition: rtltypes.h:1378
_In_ UINT _In_ UINT _In_ PNDIS_PACKET Source
Definition: ndis.h:3167
WCHAR NTAPI RtlpDowncaseUnicodeChar(IN WCHAR Source)
Definition: nls.c:89
IN PUNICODE_STRING IN PUNICODE_STRING IN PUNICODE_STRING * StringUsed
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ ULONG _Out_ PVOID _Out_ PULONG RequiredSize
Definition: wdfdevice.h:4431
#define RTL_USER_PROCESS_PARAMETERS_NORMALIZED
Definition: rtltypes.h:41
#define STATUS_SUCCESS
Definition: shellext.h:65
NTSTATUS NTAPI RtlGetLengthWithoutTrailingPathSeparators(IN ULONG Flags, IN PCUNICODE_STRING PathString, OUT PULONG Length)
Definition: path.c:1573
GLfloat GLfloat p
Definition: glext.h:8902
#define DPRINT
Definition: sndvol32.h:71
const UNICODE_STRING RtlpDosDevicesUncPrefix
Definition: path.c:36
#define __FUNCTION__
Definition: types.h:112
static SERVICE_STATUS status
Definition: service.c:31
NTSTATUS NTAPI RtlGetLengthWithoutLastFullDosOrNtPathElement(IN ULONG Flags, IN PCUNICODE_STRING Path, OUT PULONG LengthOut)
Definition: path.c:496
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
const UNICODE_STRING RtlpDoubleSlashPrefix
Definition: path.c:48
#define LOWORD(l)
Definition: pedump.c:82
_Inout_opt_ PUNICODE_STRING Extension
Definition: fltkernel.h:1092
IN PUNICODE_STRING StaticString
ULONG NTAPI RtlIsDosDeviceName_U(IN PCWSTR Path)
Definition: path.c:1639
NTSTATUS NTAPI RtlDosSearchPath_Ustr(IN ULONG Flags, IN PUNICODE_STRING PathString, IN PUNICODE_STRING FileNameString, IN PUNICODE_STRING ExtensionString, IN PUNICODE_STRING CallerBuffer, IN OUT PUNICODE_STRING DynamicString OPTIONAL, OUT PUNICODE_STRING *FullNameOut OPTIONAL, OUT PSIZE_T FilePartSize OPTIONAL, OUT PSIZE_T LengthNeeded OPTIONAL)
Definition: path.c:2559
const UNICODE_STRING DeviceRootString
Definition: path.c:34
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
IN PUNICODE_STRING IN PUNICODE_STRING DynamicString
Definition: ps.c:97
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68