ReactOS  0.4.14-dev-49-gfb4591c
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 PVOID LengthFunction)
450 {
452  return STATUS_NOT_IMPLEMENTED;
453 }
454 
455 NTSTATUS
456 NTAPI
458  IN PWCHAR Path,
459  OUT PULONG LengthOut)
460 {
462  return STATUS_NOT_IMPLEMENTED;
463 }
464 
465 NTSTATUS
466 NTAPI
468  _In_ PUNICODE_STRING DllName,
469  _Inout_ PUNICODE_STRING RealName,
470  _Inout_ PUNICODE_STRING LocalName)
471 {
472  static const UNICODE_STRING ExtensionChar = RTL_CONSTANT_STRING(L".");
473 
475  UNICODE_STRING ImagePathName, DllNameOnly, CopyRealName, CopyLocalName;
476  BOOLEAN HasExtension;
479  C_ASSERT(sizeof(UNICODE_NULL) == sizeof(WCHAR));
480 
481  CopyRealName = *RealName;
482  CopyLocalName = *LocalName;
483 
484 
485  /* Get the image path */
487 
488  /* Check if it's not normalized */
489  if (!(RtlGetCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
490  {
491  /* Normalize it */
492  ImagePathName.Buffer = (PWSTR)((ULONG_PTR)ImagePathName.Buffer + (ULONG_PTR)RtlGetCurrentPeb()->ProcessParameters);
493  }
494 
495 
496  if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
497  DllName, &RtlpPathDividers, &Position)))
498  {
499  DllNameOnly = *DllName;
500  }
501  else
502  {
503  /* Just keep the dll name, ignore path components */
504  Position += sizeof(WCHAR);
505  DllNameOnly.Buffer = DllName->Buffer + Position / sizeof(WCHAR);
506  DllNameOnly.Length = DllName->Length - Position;
507  DllNameOnly.MaximumLength = DllName->MaximumLength - Position;
508  }
509 
510  if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
511  &DllNameOnly, &ExtensionChar, &Position)))
512  {
513  Position = 0;
514  }
515 
516  HasExtension = Position > 1;
517 
518  /* First we create the c:\path\processname.exe.Local\something.dll path */
519  RequiredSize = ImagePathName.Length + RtlpDotLocal.Length + DllNameOnly.Length +
520  (HasExtension ? 0 : RtlpDefaultExtension.Length) + sizeof(UNICODE_NULL);
521 
522  /* This is not going to work out */
524  return STATUS_NAME_TOO_LONG;
525 
526  /* We need something extra */
527  if (RequiredSize > CopyLocalName.MaximumLength)
528  {
530  if (CopyLocalName.Buffer == NULL)
531  return STATUS_NO_MEMORY;
532  CopyLocalName.MaximumLength = RequiredSize;
533  }
534  /* Now build the entire path */
535  CopyLocalName.Length = 0;
536  Status = RtlAppendUnicodeStringToString(&CopyLocalName, &ImagePathName);
538  if (NT_SUCCESS(Status))
539  {
542  }
543  if (NT_SUCCESS(Status))
544  {
545  Status = RtlAppendUnicodeStringToString(&CopyLocalName, &DllNameOnly);
547  }
548  /* Do we need to append an extension? */
549  if (NT_SUCCESS(Status) && !HasExtension)
550  {
553  }
554 
555  if (NT_SUCCESS(Status))
556  {
557  /* then we create the c:\path\something.dll path */
558  if (NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
559  &ImagePathName, &RtlpPathDividers, &Position)))
560  {
561  ImagePathName.Length = Position + sizeof(WCHAR);
562  }
563 
564  RequiredSize = ImagePathName.Length + DllNameOnly.Length +
565  (HasExtension ? 0 : RtlpDefaultExtension.Length) + sizeof(UNICODE_NULL);
566 
568  {
570  }
571  else
572  {
573  if (RequiredSize > CopyRealName.MaximumLength)
574  {
576  if (CopyRealName.Buffer == NULL)
578  CopyRealName.MaximumLength = RequiredSize;
579  }
580  CopyRealName.Length = 0;
581  if (NT_SUCCESS(Status))
582  {
583  Status = RtlAppendUnicodeStringToString(&CopyRealName, &ImagePathName);
585  }
586  if (NT_SUCCESS(Status))
587  {
588  Status = RtlAppendUnicodeStringToString(&CopyRealName, &DllNameOnly);
590  }
591  if (NT_SUCCESS(Status) && !HasExtension)
592  {
595  }
596  }
597  }
598 
599  if (!NT_SUCCESS(Status))
600  {
601  if (CopyRealName.Buffer && CopyRealName.Buffer != RealName->Buffer)
602  RtlpFreeStringMemory(CopyRealName.Buffer, TAG_USTR);
603  if (CopyLocalName.Buffer && CopyLocalName.Buffer != LocalName->Buffer)
604  RtlpFreeStringMemory(CopyLocalName.Buffer, TAG_USTR);
605  return Status;
606  }
607 
608  *RealName = CopyRealName;
609  *LocalName = CopyLocalName;
610  return STATUS_SUCCESS;
611 }
612 
613 ULONG
614 NTAPI
617  _In_ ULONG Size,
622 {
625  ULONG FileNameLength, FileNameChars, DosLength, DosLengthOffset, FullLength;
626  BOOLEAN SkipTrailingPathSeparators;
627  WCHAR c;
628 
629 
630  ULONG reqsize = 0;
631  PCWSTR ptr;
632 
633  PCUNICODE_STRING CurDirName;
634  UNICODE_STRING EnvVarName, EnvVarValue;
635  WCHAR EnvVarNameBuffer[4];
636 
637  ULONG PrefixCut = 0; // Where the path really starts (after the skipped prefix)
638  PWCHAR Prefix = NULL; // pointer to the string to be inserted as the new path prefix
639  ULONG PrefixLength = 0;
640  PWCHAR Source;
641  ULONG SourceLength;
642 
643 
644  /* For now, assume the name is valid */
645  DPRINT("Filename: %wZ\n", FileName);
646  DPRINT("Size and buffer: %lx %p\n", Size, Buffer);
647  if (InvalidName) *InvalidName = FALSE;
648 
649  /* Handle initial path type and failure case */
651  if ((FileName->Length == 0) || (FileName->Buffer[0] == UNICODE_NULL)) return 0;
652 
653  /* Break filename into component parts */
654  FileNameBuffer = FileName->Buffer;
655  FileNameLength = FileName->Length;
656  FileNameChars = FileNameLength / sizeof(WCHAR);
657 
658  /* Kill trailing spaces */
659  c = FileNameBuffer[FileNameChars - 1];
660  while ((FileNameLength != 0) && (c == L' '))
661  {
662  /* Keep going, ignoring the spaces */
663  FileNameLength -= sizeof(WCHAR);
664  if (FileNameLength != 0) c = FileNameBuffer[FileNameLength / sizeof(WCHAR) - 1];
665  }
666 
667  /* Check if anything is left */
668  if (FileNameLength == 0) return 0;
669 
670  /*
671  * Check whether we'll need to skip trailing path separators in the
672  * computed full path name. If the original file name already contained
673  * trailing separators, then we keep them in the full path name. On the
674  * other hand, if the original name didn't contain any trailing separators
675  * then we'll skip it in the full path name.
676  */
677  SkipTrailingPathSeparators = !IS_PATH_SEPARATOR(FileNameBuffer[FileNameChars - 1]);
678 
679  /* Check if this is a DOS name */
680  DosLength = RtlIsDosDeviceName_Ustr(FileName);
681  DPRINT("DOS length for filename: %lx %wZ\n", DosLength, FileName);
682  if (DosLength != 0)
683  {
684  /* Zero out the short name */
685  if (ShortName) *ShortName = NULL;
686 
687  /* See comment for RtlIsDosDeviceName_Ustr if this is confusing... */
688  DosLengthOffset = HIWORD(DosLength);
689  DosLength = LOWORD(DosLength);
690 
691  /* Do we have a DOS length, and does the caller want validity? */
692  if (InvalidName && (DosLengthOffset != 0))
693  {
694  /* Do the check */
695  Status = RtlpCheckDeviceName(FileName, DosLengthOffset, InvalidName);
696 
697  /* If the check failed, or the name is invalid, fail here */
698  if (!NT_SUCCESS(Status)) return 0;
699  if (*InvalidName) return 0;
700  }
701 
702  /* Add the size of the device root and check if it fits in the size */
703  FullLength = DosLength + DeviceRootString.Length;
704  if (FullLength < Size)
705  {
706  /* Add the device string */
708 
709  /* Now add the DOS device name */
711  (PCHAR)FileNameBuffer + DosLengthOffset,
712  DosLength);
713 
714  /* Null terminate */
715  *(PWCHAR)((ULONG_PTR)Buffer + FullLength) = UNICODE_NULL;
716  return FullLength;
717  }
718 
719  /* Otherwise, there's no space, so return the buffer size needed */
720  if ((FullLength + sizeof(UNICODE_NULL)) > UNICODE_STRING_MAX_BYTES) return 0;
721  return FullLength + sizeof(UNICODE_NULL);
722  }
723 
724  /* Zero-out the destination buffer. FileName must be different from Buffer */
726 
727  /* Get the path type */
729 
730 
731 
732  /**********************************************
733  ** CODE REWRITING IS HAPPENING THERE **
734  **********************************************/
736  SourceLength = FileNameLength;
737  EnvVarValue.Buffer = NULL;
738 
739  /* Lock the PEB to get the current directory */
741  CurDirName = &NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath;
742 
743  switch (*PathType)
744  {
745  case RtlPathTypeUncAbsolute: /* \\foo */
746  {
747  PrefixCut = RtlpSkipUNCPrefix(FileNameBuffer);
748  break;
749  }
750 
751  case RtlPathTypeLocalDevice: /* \\.\foo */
752  {
753  PrefixCut = 4;
754  break;
755  }
756 
757  case RtlPathTypeDriveAbsolute: /* c:\foo */
758  {
759  ASSERT(FileNameBuffer[1] == L':');
761 
762  // FileNameBuffer[0] = RtlpUpcaseUnicodeChar(FileNameBuffer[0]);
764  PrefixLength = 3 * sizeof(WCHAR);
765  Source += 3;
766  SourceLength -= 3 * sizeof(WCHAR);
767 
768  PrefixCut = 3;
769  break;
770  }
771 
772  case RtlPathTypeDriveRelative: /* c:foo */
773  {
774  WCHAR CurDrive, NewDrive;
775 
776  Source += 2;
777  SourceLength -= 2 * sizeof(WCHAR);
778 
779  CurDrive = RtlpUpcaseUnicodeChar(CurDirName->Buffer[0]);
780  NewDrive = RtlpUpcaseUnicodeChar(FileNameBuffer[0]);
781 
782  if ((NewDrive != CurDrive) || CurDirName->Buffer[1] != L':')
783  {
784  EnvVarNameBuffer[0] = L'=';
785  EnvVarNameBuffer[1] = NewDrive;
786  EnvVarNameBuffer[2] = L':';
787  EnvVarNameBuffer[3] = UNICODE_NULL;
788 
789  EnvVarName.Length = 3 * sizeof(WCHAR);
790  EnvVarName.MaximumLength = EnvVarName.Length + sizeof(WCHAR);
791  EnvVarName.Buffer = EnvVarNameBuffer;
792 
793  // FIXME: Is it possible to use the user-given buffer ?
794  // RtlInitEmptyUnicodeString(&EnvVarValue, NULL, Size);
795  EnvVarValue.Length = 0;
796  EnvVarValue.MaximumLength = (USHORT)Size;
797  EnvVarValue.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
798  if (EnvVarValue.Buffer == NULL)
799  {
800  Prefix = NULL;
801  PrefixLength = 0;
802  goto Quit;
803  }
804 
805  Status = RtlQueryEnvironmentVariable_U(NULL, &EnvVarName, &EnvVarValue);
806  switch (Status)
807  {
808  case STATUS_SUCCESS:
809  /*
810  * (From Wine)
811  * FIXME: Win2k seems to check that the environment
812  * variable actually points to an existing directory.
813  * If not, root of the drive is used (this seems also
814  * to be the only place in RtlGetFullPathName that the
815  * existence of a part of a path is checked).
816  */
817  EnvVarValue.Buffer[EnvVarValue.Length / sizeof(WCHAR)] = L'\\';
818  Prefix = EnvVarValue.Buffer;
819  PrefixLength = EnvVarValue.Length + sizeof(WCHAR); /* Append trailing '\\' */
820  break;
821 
823  reqsize = EnvVarValue.Length + SourceLength + sizeof(UNICODE_NULL);
824  goto Quit;
825 
826  default:
827  DPRINT1("RtlQueryEnvironmentVariable_U(\"%wZ\") returned 0x%08lx\n", &EnvVarName, Status);
828 
829  EnvVarNameBuffer[0] = NewDrive;
830  EnvVarNameBuffer[1] = L':';
831  EnvVarNameBuffer[2] = L'\\';
832  EnvVarNameBuffer[3] = UNICODE_NULL;
833  Prefix = EnvVarNameBuffer;
834  PrefixLength = 3 * sizeof(WCHAR);
835 
836  RtlFreeHeap(RtlGetProcessHeap(), 0, EnvVarValue.Buffer);
837  EnvVarValue.Buffer = NULL;
838  break;
839  }
840  PrefixCut = 3;
841  break;
842  }
843  /* Fall through */
844  DPRINT("RtlPathTypeDriveRelative - Using fall-through to RtlPathTypeRelative\n");
845  }
846 
847  case RtlPathTypeRelative: /* foo */
848  {
849  Prefix = CurDirName->Buffer;
850  PrefixLength = CurDirName->Length;
851  if (CurDirName->Buffer[1] != L':')
852  {
853  PrefixCut = RtlpSkipUNCPrefix(CurDirName->Buffer);
854  }
855  else
856  {
857  PrefixCut = 3;
858  }
859  break;
860  }
861 
862  case RtlPathTypeRooted: /* \xxx */
863  {
864  if (CurDirName->Buffer[1] == L':')
865  {
866  // The path starts with "C:\"
867  ASSERT(CurDirName->Buffer[1] == L':');
868  ASSERT(IS_PATH_SEPARATOR(CurDirName->Buffer[2]));
869 
870  Prefix = CurDirName->Buffer;
871  PrefixLength = 3 * sizeof(WCHAR); // Skip "C:\"
872 
873  PrefixCut = 3; // Source index location incremented of + 3
874  }
875  else
876  {
877  PrefixCut = RtlpSkipUNCPrefix(CurDirName->Buffer);
878  PrefixLength = PrefixCut * sizeof(WCHAR);
879  Prefix = CurDirName->Buffer;
880  }
881  break;
882  }
883 
884  case RtlPathTypeRootLocalDevice: /* \\. */
885  {
887  PrefixLength = DeviceRootString.Length;
888  Source += 3;
889  SourceLength -= 3 * sizeof(WCHAR);
890 
891  PrefixCut = 4;
892  break;
893  }
894 
895  case RtlPathTypeUnknown:
896  goto Quit;
897  }
898 
899  /* Do we have enough space for storing the full path? */
900  reqsize = PrefixLength;
901  if (reqsize + SourceLength + sizeof(WCHAR) > Size)
902  {
903  /* Not enough space, return needed size (including terminating '\0') */
904  reqsize += SourceLength + sizeof(WCHAR);
905  goto Quit;
906  }
907 
908  /*
909  * Build the full path
910  */
911  /* Copy the path's prefix */
912  if (PrefixLength) RtlMoveMemory(Buffer, Prefix, PrefixLength);
913  /* Copy the remaining part of the path */
914  RtlMoveMemory(Buffer + PrefixLength / sizeof(WCHAR), Source, SourceLength + sizeof(WCHAR));
915 
916  /* Some cleanup */
917  Prefix = NULL;
918  if (EnvVarValue.Buffer)
919  {
920  RtlFreeHeap(RtlGetProcessHeap(), 0, EnvVarValue.Buffer);
921  EnvVarValue.Buffer = NULL;
922  }
923 
924  /*
925  * Finally, put the path in canonical form (remove redundant . and ..,
926  * (back)slashes...) and retrieve the length of the full path name
927  * (without its terminating null character) (in chars).
928  */
929  reqsize = RtlpCollapsePath(Buffer, /* Size, reqsize, */ PrefixCut, SkipTrailingPathSeparators);
930 
931  /* Find the file part, which is present after the last path separator */
932  if (ShortName)
933  {
934  ptr = wcsrchr(Buffer, L'\\');
935  if (ptr) ++ptr; // Skip it
936 
937  /*
938  * For UNC paths, the file part is after the \\share\dir part of the path.
939  */
940  PrefixCut = (*PathType == RtlPathTypeUncAbsolute ? PrefixCut : 3);
941 
942  if (ptr && *ptr && (ptr >= Buffer + PrefixCut))
943  {
944  *ShortName = ptr;
945  }
946  else
947  {
948  /* Zero-out the short name */
949  *ShortName = NULL;
950  }
951  }
952 
953 Quit:
954  /* Release PEB lock */
956 
957  return reqsize;
958 }
959 
960 NTSTATUS
961 NTAPI
963  OUT PUNICODE_STRING NtPath,
964  OUT PCWSTR *PartName,
965  OUT PRTL_RELATIVE_NAME_U RelativeName)
966 {
967  ULONG DosLength;
968  PWSTR NewBuffer, p;
969 
970  /* Validate the input */
971  if (!DosPath) return STATUS_OBJECT_NAME_INVALID;
972 
973  /* Validate the DOS length */
974  DosLength = DosPath->Length;
975  if (DosLength >= UNICODE_STRING_MAX_BYTES) return STATUS_NAME_TOO_LONG;
976 
977  /* Make space for the new path */
978  NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
979  0,
980  DosLength + sizeof(UNICODE_NULL));
981  if (!NewBuffer) return STATUS_NO_MEMORY;
982 
983  /* Copy the prefix, and then the rest of the DOS path, and NULL-terminate */
986  DosPath->Buffer + RtlpDosDevicesPrefix.Length / sizeof(WCHAR),
987  DosPath->Length - RtlpDosDevicesPrefix.Length);
988  NewBuffer[DosLength / sizeof(WCHAR)] = UNICODE_NULL;
989 
990  /* Did the caller send a relative name? */
991  if (RelativeName)
992  {
993  /* Zero initialize it */
994  RtlInitEmptyUnicodeString(&RelativeName->RelativeName, NULL, 0);
995  RelativeName->ContainingDirectory = NULL;
996  RelativeName->CurDirRef = 0;
997  }
998 
999  /* Did the caller request a partial name? */
1000  if (PartName)
1001  {
1002  /* Loop from the back until we find a path separator */
1003  p = &NewBuffer[DosLength / sizeof(WCHAR)];
1004  while (--p > NewBuffer)
1005  {
1006  /* We found a path separator, move past it */
1007  if (*p == OBJ_NAME_PATH_SEPARATOR)
1008  {
1009  ++p;
1010  break;
1011  }
1012  }
1013 
1014  /* Check whether a separator was found and if something remains */
1015  if ((p > NewBuffer) && *p)
1016  {
1017  /* What follows the path separator is the partial name */
1018  *PartName = p;
1019  }
1020  else
1021  {
1022  /* The path ends with a path separator, no partial name */
1023  *PartName = NULL;
1024  }
1025  }
1026 
1027  /* Build the final NT path string */
1028  NtPath->Buffer = NewBuffer;
1029  NtPath->Length = (USHORT)DosLength;
1030  NtPath->MaximumLength = (USHORT)DosLength + sizeof(UNICODE_NULL);
1031  return STATUS_SUCCESS;
1032 }
1033 
1034 NTSTATUS
1035 NTAPI
1038  OUT PUNICODE_STRING NtName,
1039  OUT PCWSTR *PartName,
1040  OUT PRTL_RELATIVE_NAME_U RelativeName)
1041 {
1042  WCHAR BigBuffer[MAX_PATH + 1];
1043  PWCHAR PrefixBuffer, NewBuffer, Buffer;
1044  ULONG MaxLength, PathLength, PrefixLength, PrefixCut, LengthChars, Length;
1045  UNICODE_STRING CapturedDosName, PartNameString, FullPath;
1046  BOOLEAN QuickPath;
1047  RTL_PATH_TYPE InputPathType, BufferPathType;
1048  NTSTATUS Status;
1051 
1052  /* Assume MAX_PATH for now */
1053  DPRINT("Relative: %lx DosName: %wZ NtName: %p, PartName: %p, RelativeName: %p\n",
1054  HaveRelative, DosName, NtName, PartName, RelativeName);
1055  MaxLength = sizeof(BigBuffer);
1056 
1057  /* Validate the input */
1058  if (!DosName) return STATUS_OBJECT_NAME_INVALID;
1059 
1060  /* Capture input string */
1061  CapturedDosName = *DosName;
1062 
1063  /* Check for the presence or absence of the NT prefix "\\?\" form */
1064  // if (!RtlPrefixUnicodeString(&RtlpWin32NtRootSlash, &CapturedDosName, FALSE))
1065  if ((CapturedDosName.Length <= RtlpWin32NtRootSlash.Length) ||
1066  (CapturedDosName.Buffer[0] != RtlpWin32NtRootSlash.Buffer[0]) ||
1067  (CapturedDosName.Buffer[1] != RtlpWin32NtRootSlash.Buffer[1]) ||
1068  (CapturedDosName.Buffer[2] != RtlpWin32NtRootSlash.Buffer[2]) ||
1069  (CapturedDosName.Buffer[3] != RtlpWin32NtRootSlash.Buffer[3]))
1070  {
1071  /* NT prefix not present */
1072 
1073  /* Quick path won't be used */
1074  QuickPath = FALSE;
1075 
1076  /* Use the static buffer */
1077  Buffer = BigBuffer;
1078  MaxLength += RtlpDosDevicesUncPrefix.Length;
1079 
1080  /* Allocate a buffer to hold the path */
1081  NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, MaxLength);
1082  DPRINT("MaxLength: %lx\n", MaxLength);
1083  if (!NewBuffer) return STATUS_NO_MEMORY;
1084  }
1085  else
1086  {
1087  /* NT prefix present */
1088 
1089  /* Use the optimized path after acquiring the lock */
1090  QuickPath = TRUE;
1091  NewBuffer = NULL;
1092  }
1093 
1094  /* Lock the PEB and check if the quick path can be used */
1096  if (QuickPath)
1097  {
1098  /* Some simple fixups will get us the correct path */
1099  DPRINT("Quick path\n");
1100  Status = RtlpWin32NTNameToNtPathName_U(&CapturedDosName,
1101  NtName,
1102  PartName,
1103  RelativeName);
1104 
1105  /* Release the lock, we're done here */
1107  return Status;
1108  }
1109 
1110  /* Call the main function to get the full path name and length */
1111  PathLength = RtlGetFullPathName_Ustr(&CapturedDosName,
1112  MAX_PATH * sizeof(WCHAR),
1113  Buffer,
1114  PartName,
1115  &NameInvalid,
1116  &InputPathType);
1117  if ((NameInvalid) || !(PathLength) || (PathLength > (MAX_PATH * sizeof(WCHAR))))
1118  {
1119  /* Invalid name, fail */
1120  DPRINT("Invalid name: %lx Path Length: %lx\n", NameInvalid, PathLength);
1121  RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
1124  }
1125 
1126  /* Start by assuming the path starts with \??\ (DOS Devices Path) */
1127  PrefixLength = RtlpDosDevicesPrefix.Length;
1128  PrefixBuffer = RtlpDosDevicesPrefix.Buffer;
1129  PrefixCut = 0;
1130 
1131  /* Check where it really is */
1132  BufferPathType = RtlDetermineDosPathNameType_U(Buffer);
1133  DPRINT("Buffer: %S Type: %lx\n", Buffer, BufferPathType);
1134  switch (BufferPathType)
1135  {
1136  /* It's actually a UNC path in \??\UNC\ */
1138  PrefixLength = RtlpDosDevicesUncPrefix.Length;
1139  PrefixBuffer = RtlpDosDevicesUncPrefix.Buffer;
1140  PrefixCut = 2;
1141  break;
1142 
1144  /* We made a good guess, go with it but skip the \??\ */
1145  PrefixCut = 4;
1146  break;
1147 
1150  case RtlPathTypeRooted:
1151  case RtlPathTypeRelative:
1152  /* Our guess was good, roll with it */
1153  break;
1154 
1155  /* Nothing else is expected */
1156  default:
1157  ASSERT(FALSE);
1158  }
1159 
1160  /* Now copy the prefix and the buffer */
1161  RtlCopyMemory(NewBuffer, PrefixBuffer, PrefixLength);
1162  RtlCopyMemory((PCHAR)NewBuffer + PrefixLength,
1163  Buffer + PrefixCut,
1164  PathLength - (PrefixCut * sizeof(WCHAR)));
1165 
1166  /* Compute the length */
1167  Length = PathLength + PrefixLength - PrefixCut * sizeof(WCHAR);
1168  LengthChars = Length / sizeof(WCHAR);
1169 
1170  /* Setup the actual NT path string and terminate it */
1171  NtName->Buffer = NewBuffer;
1172  NtName->Length = (USHORT)Length;
1173  NtName->MaximumLength = (USHORT)MaxLength;
1174  NewBuffer[LengthChars] = UNICODE_NULL;
1175  DPRINT("New buffer: %S\n", NewBuffer);
1176  DPRINT("NT Name: %wZ\n", NtName);
1177 
1178  /* Check if a partial name was requested */
1179  if ((PartName) && (*PartName))
1180  {
1181  /* Convert to Unicode */
1182  Status = RtlInitUnicodeStringEx(&PartNameString, *PartName);
1183  if (NT_SUCCESS(Status))
1184  {
1185  /* Set the partial name */
1186  *PartName = &NewBuffer[LengthChars - (PartNameString.Length / sizeof(WCHAR))];
1187  }
1188  else
1189  {
1190  /* Fail */
1191  RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
1193  return Status;
1194  }
1195  }
1196 
1197  /* Check if a relative name was asked for */
1198  if (RelativeName)
1199  {
1200  /* Setup the structure */
1201  RtlInitEmptyUnicodeString(&RelativeName->RelativeName, NULL, 0);
1202  RelativeName->ContainingDirectory = NULL;
1203  RelativeName->CurDirRef = NULL;
1204 
1205  /* Check if the input path itself was relative */
1206  if (InputPathType == RtlPathTypeRelative)
1207  {
1208  /* Get current directory */
1209  CurrentDirectory = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
1210  if (CurrentDirectory->Handle)
1211  {
1212  Status = RtlInitUnicodeStringEx(&FullPath, Buffer);
1213  if (!NT_SUCCESS(Status))
1214  {
1215  RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
1217  return Status;
1218  }
1219 
1220  /* If current directory is bigger than full path, there's no way */
1221  if (CurrentDirectory->DosPath.Length > FullPath.Length)
1222  {
1224  return Status;
1225  }
1226 
1227  /* File is in current directory */
1228  if (RtlEqualUnicodeString(&FullPath, &CurrentDirectory->DosPath, TRUE))
1229  {
1230  /* Make relative name string */
1231  RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)NewBuffer + PrefixLength + FullPath.Length - PrefixCut * sizeof(WCHAR));
1232  RelativeName->RelativeName.Length = (USHORT)(PathLength - FullPath.Length);
1233  /* If relative name starts with \, skip it */
1234  if (RelativeName->RelativeName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
1235  {
1236  RelativeName->RelativeName.Buffer++;
1237  RelativeName->RelativeName.Length -= sizeof(WCHAR);
1238  }
1239  RelativeName->RelativeName.MaximumLength = RelativeName->RelativeName.Length;
1240  DPRINT("RelativeName: %wZ\n", &(RelativeName->RelativeName));
1241 
1242  if (!HaveRelative)
1243  {
1244  RelativeName->ContainingDirectory = CurrentDirectory->Handle;
1245  return Status;
1246  }
1247 
1248  /* Give back current directory data & reference counter */
1249  RelativeName->CurDirRef = RtlpCurDirRef;
1250  if (RelativeName->CurDirRef)
1251  {
1253  }
1254 
1255  RelativeName->ContainingDirectory = CurrentDirectory->Handle;
1256  }
1257  }
1258  }
1259  }
1260 
1261  /* Done */
1263  return STATUS_SUCCESS;
1264 }
1265 
1266 NTSTATUS
1267 NTAPI
1269  IN PCWSTR DosName,
1270  OUT PUNICODE_STRING NtName,
1271  OUT PCWSTR *PartName,
1272  OUT PRTL_RELATIVE_NAME_U RelativeName)
1273 {
1274  NTSTATUS Status;
1275  UNICODE_STRING NameString;
1276 
1277  /* Create the unicode name */
1278  Status = RtlInitUnicodeStringEx(&NameString, DosName);
1279  if (NT_SUCCESS(Status))
1280  {
1281  /* Call the unicode function */
1283  &NameString,
1284  NtName,
1285  PartName,
1286  RelativeName);
1287  }
1288 
1289  /* Return status */
1290  return Status;
1291 }
1292 
1293 BOOLEAN
1294 NTAPI
1296  OUT PUNICODE_STRING NtName,
1297  OUT PCWSTR *PartName,
1298  OUT PRTL_RELATIVE_NAME_U RelativeName)
1299 {
1300  /* Call the internal function */
1301  ASSERT(RelativeName);
1303  DosName,
1304  NtName,
1305  PartName,
1306  RelativeName));
1307 }
1308 
1309 BOOLEAN
1310 NTAPI
1313 {
1314  BOOLEAN Result;
1315  RTL_RELATIVE_NAME_U RelativeName;
1316  UNICODE_STRING NtPathName;
1317  PVOID Buffer;
1319  NTSTATUS Status;
1320  FILE_BASIC_INFORMATION BasicInformation;
1321 
1322  /* Get the NT Path */
1324  &NtPathName,
1325  NULL,
1326  &RelativeName);
1327  if (!Result) return FALSE;
1328 
1329  /* Save the buffer */
1330  Buffer = NtPathName.Buffer;
1331 
1332  /* Check if we have a relative name */
1333  if (RelativeName.RelativeName.Length)
1334  {
1335  /* Use it */
1336  NtPathName = RelativeName.RelativeName;
1337  }
1338  else
1339  {
1340  /* Otherwise ignore it */
1341  RelativeName.ContainingDirectory = NULL;
1342  }
1343 
1344  /* Initialize the object attributes */
1346  &NtPathName,
1348  RelativeName.ContainingDirectory,
1349  NULL);
1350 
1351  /* Query the attributes and free the buffer now */
1352  Status = ZwQueryAttributesFile(&ObjectAttributes, &BasicInformation);
1353  RtlReleaseRelativeName(&RelativeName);
1354  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1355 
1356  /* Check if we failed */
1357  if (!NT_SUCCESS(Status))
1358  {
1359  /* Check if we failed because the file is in use */
1360  if ((Status == STATUS_SHARING_VIOLATION) ||
1362  {
1363  /* Check if the caller wants this to be considered OK */
1365  }
1366  else
1367  {
1368  /* A failure because the file didn't exist */
1369  Result = FALSE;
1370  }
1371  }
1372  else
1373  {
1374  /* The file exists */
1375  Result = TRUE;
1376  }
1377 
1378  /* Return the result */
1379  return Result;
1380 }
1381 
1382 BOOLEAN
1383 NTAPI
1385 {
1386  /* Call the updated API */
1388 }
1389 
1390 BOOLEAN
1391 NTAPI
1394 {
1395  UNICODE_STRING NameString;
1396 
1397  /* Create the unicode name*/
1398  if (NT_SUCCESS(RtlInitUnicodeStringEx(&NameString, FileName)))
1399  {
1400  /* Call the unicode function */
1401  return RtlDoesFileExists_UstrEx(&NameString, SucceedIfBusy);
1402  }
1403 
1404  /* Fail */
1405  return FALSE;
1406 }
1407 
1408 /* PUBLIC FUNCTIONS ***********************************************************/
1409 
1410 /*
1411  * @implemented
1412  */
1413 VOID
1414 NTAPI
1416 {
1417  /* Check if a directory reference was grabbed */
1418  if (RelativeName->CurDirRef)
1419  {
1420  /* Decrease reference count */
1421  if (!InterlockedDecrement(&RelativeName->CurDirRef->RefCount))
1422  {
1423  /* If no one uses it any longer, close handle & free */
1424  NtClose(RelativeName->CurDirRef->Handle);
1425  RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeName->CurDirRef);
1426  }
1427  RelativeName->CurDirRef = NULL;
1428  }
1429 }
1430 
1431 /*
1432  * @implemented
1433  */
1434 ULONG
1435 NTAPI
1437 {
1438  /*
1439  * The longest NT path is a DOS path that actually sits on a UNC path (ie:
1440  * a mapped network drive), which is accessed through the DOS Global?? path.
1441  * This is, and has always been equal to, 269 characters, except in Wine
1442  * which claims this is 277. Go figure.
1443  */
1444  return MAX_PATH + RtlpDosDevicesUncPrefix.Length / sizeof(WCHAR) + sizeof(ANSI_NULL);
1445 }
1446 
1447 /*
1448  * @implemented
1449  * @note: the export is called RtlGetLengthWithoutTrailingPathSeperators
1450  * (with a 'e' instead of a 'a' in "Seperators").
1451  */
1452 NTSTATUS
1453 NTAPI
1455  IN PCUNICODE_STRING PathString,
1456  OUT PULONG Length)
1457 {
1458  ULONG NumChars;
1459 
1460  /* Parameters validation */
1461  if (Length == NULL) return STATUS_INVALID_PARAMETER;
1462 
1463  *Length = 0;
1464 
1465  if (PathString == NULL) return STATUS_INVALID_PARAMETER;
1466 
1467  /* No flags are supported yet */
1468  if (Flags != 0) return STATUS_INVALID_PARAMETER;
1469 
1470  NumChars = PathString->Length / sizeof(WCHAR);
1471 
1472  /*
1473  * Notice that we skip the last character, therefore:
1474  * - if we have: "some/path/f" we test for: "some/path/"
1475  * - if we have: "some/path/" we test for: "some/path"
1476  * - if we have: "s" we test for: ""
1477  * - if we have: "" then NumChars was already zero and we aren't there
1478  */
1479 
1480  while (NumChars > 0 && IS_PATH_SEPARATOR(PathString->Buffer[NumChars - 1]))
1481  {
1482  --NumChars;
1483  }
1484 
1485  *Length = NumChars;
1486  return STATUS_SUCCESS;
1487 }
1488 
1489 /*
1490  * @implemented
1491  */
1493 NTAPI
1495 {
1496  DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
1497 
1498  /* Unlike the newer RtlDetermineDosPathNameType_U we assume 4 characters */
1499  if (IS_PATH_SEPARATOR(Path[0]))
1500  {
1501  if (!IS_PATH_SEPARATOR(Path[1])) return RtlPathTypeRooted; /* \x */
1502  if ((Path[2] != L'.') && (Path[2] != L'?')) return RtlPathTypeUncAbsolute;/* \\x */
1503  if (IS_PATH_SEPARATOR(Path[3])) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */
1504  if (Path[3]) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */
1505  return RtlPathTypeRootLocalDevice; /* \\. or \\? */
1506  }
1507  else
1508  {
1509  if (!(Path[0]) || (Path[1] != L':')) return RtlPathTypeRelative; /* x */
1510  if (IS_PATH_SEPARATOR(Path[2])) return RtlPathTypeDriveAbsolute; /* x:\ */
1511  return RtlPathTypeDriveRelative; /* x: */
1512  }
1513 }
1514 
1515 /*
1516  * @implemented
1517  */
1518 ULONG
1519 NTAPI
1521 {
1522  UNICODE_STRING PathString;
1523  NTSTATUS Status;
1524 
1525  /* Build the string */
1526  Status = RtlInitUnicodeStringEx(&PathString, Path);
1527  if (!NT_SUCCESS(Status)) return 0;
1528 
1529  /*
1530  * Returns 0 if name is not valid DOS device name, or DWORD with
1531  * offset in bytes to DOS device name from beginning of buffer in high word
1532  * and size in bytes of DOS device name in low word
1533  */
1534  return RtlIsDosDeviceName_Ustr(&PathString);
1535 }
1536 
1537 /*
1538  * @implemented
1539  */
1540 ULONG
1541 NTAPI
1545 {
1546  ULONG Length, Bytes;
1547  PCURDIR CurDir;
1548  PWSTR CurDirName;
1549  DPRINT("RtlGetCurrentDirectory %lu %p\n", MaximumLength, Buffer);
1550 
1551  /* Lock the PEB to get the current directory */
1553  CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory;
1554 
1555  /* Get the buffer and character length */
1556  CurDirName = CurDir->DosPath.Buffer;
1557  Length = CurDir->DosPath.Length / sizeof(WCHAR);
1558  ASSERT((CurDirName != NULL) && (Length > 0));
1559 
1560  /*
1561  * DosPath.Buffer should always have a trailing slash. There is an assert
1562  * below which checks for this.
1563  *
1564  * This function either returns x:\ for a root (keeping the original buffer)
1565  * or it returns x:\path\foo for a directory (replacing the trailing slash
1566  * with a NULL.
1567  */
1568  Bytes = Length * sizeof(WCHAR);
1569  if ((Length <= 1) || (CurDirName[Length - 2] == L':'))
1570  {
1571  /* Check if caller does not have enough space */
1572  if (MaximumLength <= Bytes)
1573  {
1574  /* Call has no space for it, fail, add the trailing slash */
1576  return Bytes + sizeof(OBJ_NAME_PATH_SEPARATOR);
1577  }
1578  }
1579  else
1580  {
1581  /* Check if caller does not have enough space */
1582  if (MaximumLength < Bytes)
1583  {
1584  /* Call has no space for it, fail */
1586  return Bytes;
1587  }
1588  }
1589 
1590  /* Copy the buffer since we seem to have space */
1591  RtlCopyMemory(Buffer, CurDirName, Bytes);
1592 
1593  /* The buffer should end with a path separator */
1595 
1596  /* Again check for our two cases (drive root vs path) */
1597  if ((Length <= 1) || (Buffer[Length - 2] != L':'))
1598  {
1599  /* Replace the trailing slash with a null */
1600  Buffer[Length - 1] = UNICODE_NULL;
1601  --Length;
1602  }
1603  else
1604  {
1605  /* Append the null char since there's no trailing slash */
1607  }
1608 
1609  /* Release PEB lock */
1611  DPRINT("CurrentDirectory %S\n", Buffer);
1612  return Length * sizeof(WCHAR);
1613 }
1614 
1615 /*
1616  * @implemented
1617  */
1618 NTSTATUS
1619 NTAPI
1621 {
1622  PCURDIR CurDir;
1623  NTSTATUS Status;
1626  UNICODE_STRING FullPath, NtName;
1627  PRTLP_CURDIR_REF OldCurDir = NULL;
1629  FILE_FS_DEVICE_INFORMATION FileFsDeviceInfo;
1630  ULONG SavedLength, CharLength, FullPathLength;
1631  HANDLE OldHandle = NULL, CurDirHandle = NULL, OldCurDirHandle = NULL;
1632 
1633  DPRINT("RtlSetCurrentDirectory_U %wZ\n", Path);
1634 
1635  /* Initialize for failure case */
1636  RtlInitEmptyUnicodeString(&NtName, NULL, 0);
1637 
1638  /* Can't set current directory on DOS device */
1640  {
1641  return STATUS_NOT_A_DIRECTORY;
1642  }
1643 
1644  /* Get current directory */
1646  CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory;
1647 
1648  /* Check if we have to drop current handle */
1650  {
1651  OldHandle = CurDir->Handle;
1652  CurDir->Handle = NULL;
1653  }
1654 
1655  /* Allocate a buffer for full path (using max possible length */
1656  FullPath.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, CurDir->DosPath.MaximumLength);
1657  if (!FullPath.Buffer)
1658  {
1660  goto Leave;
1661  }
1662 
1663  /* Init string */
1664  FullPath.Length = 0;
1665  FullPath.MaximumLength = CurDir->DosPath.MaximumLength;
1666 
1667  /* Get new directory full path */
1668  FullPathLength = RtlGetFullPathName_Ustr(Path, FullPath.MaximumLength, FullPath.Buffer, NULL, NULL, &PathType);
1669  if (!FullPathLength)
1670  {
1672  goto Leave;
1673  }
1674 
1675  SavedLength = FullPath.MaximumLength;
1676  CharLength = FullPathLength / sizeof(WCHAR);
1677 
1678  if (FullPathLength > FullPath.MaximumLength)
1679  {
1681  goto Leave;
1682  }
1683 
1684  /* Translate it to NT name */
1685  if (!RtlDosPathNameToNtPathName_U(FullPath.Buffer, &NtName, NULL, NULL))
1686  {
1688  goto Leave;
1689  }
1690 
1693  NULL, NULL);
1694 
1695  /* If previous current directory was removable, then check it for dropping */
1697  {
1698  /* Get back normal handle */
1699  CurDirHandle = (HANDLE)((ULONG_PTR)(CurDir->Handle) & ~RTL_CURDIR_ALL_FLAGS);
1700  CurDir->Handle = NULL;
1701 
1702  /* Get device information */
1703  Status = NtQueryVolumeInformationFile(CurDirHandle,
1704  &IoStatusBlock,
1705  &FileFsDeviceInfo,
1706  sizeof(FileFsDeviceInfo),
1708  /* Retry without taking care of removable device */
1709  if (!NT_SUCCESS(Status))
1710  {
1712  goto Leave;
1713  }
1714  }
1715  else
1716  {
1717  /* Open directory */
1718  Status = NtOpenFile(&CurDirHandle,
1721  &IoStatusBlock,
1724  if (!NT_SUCCESS(Status)) goto Leave;
1725 
1726  /* Get device information */
1727  Status = NtQueryVolumeInformationFile(CurDirHandle,
1728  &IoStatusBlock,
1729  &FileFsDeviceInfo,
1730  sizeof(FileFsDeviceInfo),
1732  if (!NT_SUCCESS(Status)) goto Leave;
1733  }
1734 
1735  /* If device is removable, mark handle */
1736  if (FileFsDeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA)
1737  {
1738  CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_CURDIR_IS_REMOVABLE);
1739  }
1740 
1741  FullPath.Length = (USHORT)FullPathLength;
1742 
1743  /* If full path isn't \ terminated, do it */
1744  if (FullPath.Buffer[CharLength - 1] != OBJ_NAME_PATH_SEPARATOR)
1745  {
1746  if ((CharLength + 1) * sizeof(WCHAR) > SavedLength)
1747  {
1749  goto Leave;
1750  }
1751 
1752  FullPath.Buffer[CharLength] = OBJ_NAME_PATH_SEPARATOR;
1753  FullPath.Buffer[CharLength + 1] = UNICODE_NULL;
1754  FullPath.Length += sizeof(WCHAR);
1755  }
1756 
1757  /* If we have previous current directory with only us as reference, save it */
1758  if (RtlpCurDirRef != NULL && RtlpCurDirRef->RefCount == 1)
1759  {
1760  OldCurDirHandle = RtlpCurDirRef->Handle;
1761  }
1762  else
1763  {
1764  /* Allocate new current directory struct saving previous one */
1765  OldCurDir = RtlpCurDirRef;
1766  RtlpCurDirRef = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTLP_CURDIR_REF));
1767  if (!RtlpCurDirRef)
1768  {
1769  RtlpCurDirRef = OldCurDir;
1770  OldCurDir = NULL;
1772  goto Leave;
1773  }
1774 
1775  /* Set reference to 1 (us) */
1776  RtlpCurDirRef->RefCount = 1;
1777  }
1778 
1779  /* Save new data */
1780  CurDir->Handle = CurDirHandle;
1781  RtlpCurDirRef->Handle = CurDirHandle;
1782  CurDirHandle = NULL;
1783 
1784  /* Copy full path */
1785  RtlCopyMemory(CurDir->DosPath.Buffer, FullPath.Buffer, FullPath.Length + sizeof(WCHAR));
1786  CurDir->DosPath.Length = FullPath.Length;
1787 
1789 
1790 Leave:
1792 
1793  if (FullPath.Buffer)
1794  {
1795  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPath.Buffer);
1796  }
1797 
1798  if (NtName.Buffer)
1799  {
1800  RtlFreeHeap(RtlGetProcessHeap(), 0, NtName.Buffer);
1801  }
1802 
1803  if (CurDirHandle) NtClose(CurDirHandle);
1804 
1805  if (OldHandle) NtClose(OldHandle);
1806 
1807  if (OldCurDirHandle) NtClose(OldCurDirHandle);
1808 
1809  if (OldCurDir && InterlockedDecrement(&OldCurDir->RefCount) == 0)
1810  {
1811  NtClose(OldCurDir->Handle);
1812  RtlFreeHeap(RtlGetProcessHeap(), 0, OldCurDir);
1813  }
1814 
1815  return Status;
1816 }
1817 
1818 /*
1819  * @implemented
1820  */
1821 ULONG
1822 NTAPI
1827  _Out_opt_ PWSTR *FilePart,
1828  _Out_opt_ RTL_PATH_TYPE *InputPathType)
1829 {
1830  UNICODE_STRING FileNameString;
1831  NTSTATUS status;
1832 
1833  if (InputPathType)
1834  *InputPathType = 0;
1835 
1836  /* Build the string */
1837  status = RtlInitUnicodeStringEx(&FileNameString, FileName);
1838  if (!NT_SUCCESS(status)) return 0;
1839 
1840  /* Call the extended function */
1841  return RtlGetFullPathName_Ustr(
1842  &FileNameString,
1843  BufferLength,
1844  Buffer,
1845  (PCWSTR*)FilePart,
1846  NULL,
1847  InputPathType);
1848 }
1849 
1850 /******************************************************************
1851  * RtlGetFullPathName_U (NTDLL.@)
1852  *
1853  * Returns the number of bytes written to buffer (not including the
1854  * terminating NULL) if the function succeeds, or the required number of bytes
1855  * (including the terminating NULL) if the buffer is too small.
1856  *
1857  * file_part will point to the filename part inside buffer (except if we use
1858  * DOS device name, in which case file_in_buf is NULL)
1859  *
1860  * @implemented
1861  */
1862 
1863 /*
1864  * @implemented
1865  */
1866 ULONG
1867 NTAPI
1870  _In_ ULONG Size,
1873 {
1875 
1876  /* Call the extended function */
1878  Size,
1879  Buffer,
1880  ShortName,
1881  &PathType);
1882 }
1883 
1884 /*
1885  * @implemented
1886  */
1887 BOOLEAN
1888 NTAPI
1890  OUT PUNICODE_STRING NtName,
1891  OUT PCWSTR *PartName,
1892  OUT PRTL_RELATIVE_NAME_U RelativeName)
1893 {
1894  /* Call the internal function */
1896  DosName,
1897  NtName,
1898  PartName,
1899  RelativeName));
1900 }
1901 
1902 /*
1903  * @implemented
1904  */
1905 NTSTATUS
1906 NTAPI
1908  OUT PUNICODE_STRING NtName,
1909  OUT PCWSTR *PartName,
1910  OUT PRTL_RELATIVE_NAME_U RelativeName)
1911 {
1912  /* Call the internal function */
1914  DosName,
1915  NtName,
1916  PartName,
1917  RelativeName);
1918 }
1919 
1920 /*
1921  * @implemented
1922  */
1923 BOOLEAN
1924 NTAPI
1926  OUT PUNICODE_STRING NtName,
1927  OUT PCWSTR *PartName,
1928  OUT PRTL_RELATIVE_NAME_U RelativeName)
1929 {
1930  /* Call the internal function */
1931  ASSERT(RelativeName);
1933  DosName,
1934  NtName,
1935  PartName,
1936  RelativeName));
1937 }
1938 
1939 /*
1940  * @implemented
1941  */
1942 NTSTATUS
1943 NTAPI
1945  OUT PUNICODE_STRING NtName,
1946  OUT PCWSTR *PartName,
1947  OUT PRTL_RELATIVE_NAME_U RelativeName)
1948 {
1949  /* Call the internal function */
1950  ASSERT(RelativeName);
1952  DosName,
1953  NtName,
1954  PartName,
1955  RelativeName);
1956 }
1957 
1958 /*
1959  * @implemented
1960  */
1964  PULONG Unknown)
1965 {
1966  PCUNICODE_STRING UsePrefix = NULL, AlternatePrefix = NULL;
1967 
1968  if (PathType)
1969  *PathType = 0;
1970 
1971  if (!Path || Flags)
1972  return STATUS_INVALID_PARAMETER;
1973 
1974  /* The initial check is done on Path->String */
1976  {
1977  UsePrefix = &RtlpDosDevicesUncPrefix;
1978  AlternatePrefix = &RtlpDoubleSlashPrefix;
1979  if (PathType)
1981  }
1983  {
1984  UsePrefix = &RtlpDosDevicesPrefix;
1985  if (PathType)
1987  }
1988 
1989  if (UsePrefix)
1990  {
1991  NTSTATUS Status;
1992 
1993  USHORT Len = Path->String.Length - UsePrefix->Length;
1994  if (AlternatePrefix)
1995  Len += AlternatePrefix->Length;
1996 
1997  Status = RtlEnsureBufferSize(0, &Path->ByteBuffer, Len);
1998  if (!NT_SUCCESS(Status))
1999  return Status;
2000 
2001  if (Len + sizeof(UNICODE_NULL) <= Path->ByteBuffer.Size)
2002  {
2003  /* Then, the contents of Path->ByteBuffer are always used... */
2004  if (AlternatePrefix)
2005  {
2006  memcpy(Path->ByteBuffer.Buffer, AlternatePrefix->Buffer, AlternatePrefix->Length);
2007  memmove(Path->ByteBuffer.Buffer + AlternatePrefix->Length, Path->ByteBuffer.Buffer + UsePrefix->Length,
2008  Len - AlternatePrefix->Length);
2009  }
2010  else
2011  {
2013  }
2015  Path->String.Length = Len;
2017  Path->String.Buffer[Len / sizeof(WCHAR)] = UNICODE_NULL;
2018  }
2019  return STATUS_SUCCESS;
2020  }
2021 
2022  if (PathType)
2023  {
2025  {
2031  break;
2032  case RtlPathTypeUnknown:
2034  case RtlPathTypeRooted:
2035  case RtlPathTypeRelative:
2037  break;
2038  }
2039  }
2040 
2041  return STATUS_SUCCESS;
2042 }
2043 
2044 /*
2045  * @implemented
2046  */
2047 ULONG
2048 NTAPI
2050  IN PCWSTR FileName,
2052  IN ULONG Size,
2053  IN PWSTR Buffer,
2054  OUT PWSTR *PartName)
2055 {
2056  NTSTATUS Status;
2057  ULONG ExtensionLength, Length, FileNameLength, PathLength;
2058  UNICODE_STRING TempString;
2059  PWCHAR NewBuffer, BufferStart;
2060  PCWSTR p;
2061 
2062  /* Check if this is an absolute path */
2064  {
2065  /* Check if the file exists */
2067  {
2068  /* Get the full name, which does the DOS lookup */
2069  return RtlGetFullPathName_U(FileName, Size, Buffer, PartName);
2070  }
2071 
2072  /* Doesn't exist, so fail */
2073  return 0;
2074  }
2075 
2076  /* Scan the filename */
2077  p = FileName;
2078  while (*p)
2079  {
2080  /* Looking for an extension */
2081  if (*p == L'.')
2082  {
2083  /* No extension string needed -- it's part of the filename */
2084  Extension = NULL;
2085  break;
2086  }
2087 
2088  /* Next character */
2089  p++;
2090  }
2091 
2092  /* Do we have an extension? */
2093  if (!Extension)
2094  {
2095  /* Nope, don't worry about one */
2096  ExtensionLength = 0;
2097  }
2098  else
2099  {
2100  /* Build a temporary string to get the extension length */
2101  Status = RtlInitUnicodeStringEx(&TempString, Extension);
2102  if (!NT_SUCCESS(Status)) return 0;
2103  ExtensionLength = TempString.Length;
2104  }
2105 
2106  /* Build a temporary string to get the path length */
2107  Status = RtlInitUnicodeStringEx(&TempString, Path);
2108  if (!NT_SUCCESS(Status)) return 0;
2109  PathLength = TempString.Length;
2110 
2111  /* Build a temporary string to get the filename length */
2112  Status = RtlInitUnicodeStringEx(&TempString, FileName);
2113  if (!NT_SUCCESS(Status)) return 0;
2114  FileNameLength = TempString.Length;
2115 
2116  /* Allocate the buffer for the new string name */
2117  NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
2118  0,
2119  FileNameLength +
2120  ExtensionLength +
2121  PathLength +
2122  3 * sizeof(WCHAR));
2123  if (!NewBuffer)
2124  {
2125  /* Fail the call */
2126  DbgPrint("%s: Failing due to out of memory (RtlAllocateHeap failure)\n",
2127  __FUNCTION__);
2128  return 0;
2129  }
2130 
2131  /* Final loop to build the path */
2132  while (TRUE)
2133  {
2134  /* Check if we have a valid character */
2135  BufferStart = NewBuffer;
2136  if (*Path)
2137  {
2138  /* Loop as long as there's no semicolon */
2139  while (*Path != L';')
2140  {
2141  /* Copy the next character */
2142  *BufferStart++ = *Path++;
2143  if (!*Path) break;
2144  }
2145 
2146  /* We found a semi-colon, to stop path processing on this loop */
2147  if (*Path == L';') ++Path;
2148  }
2149 
2150  /* Add a terminating slash if needed */
2151  if ((BufferStart != NewBuffer) && (BufferStart[-1] != OBJ_NAME_PATH_SEPARATOR))
2152  {
2153  *BufferStart++ = OBJ_NAME_PATH_SEPARATOR;
2154  }
2155 
2156  /* Bail out if we reached the end */
2157  if (!*Path) Path = NULL;
2158 
2159  /* Copy the file name and check if an extension is needed */
2160  RtlCopyMemory(BufferStart, FileName, FileNameLength);
2161  if (ExtensionLength)
2162  {
2163  /* Copy the extension too */
2164  RtlCopyMemory((PCHAR)BufferStart + FileNameLength,
2165  Extension,
2166  ExtensionLength + sizeof(WCHAR));
2167  }
2168  else
2169  {
2170  /* Just NULL-terminate */
2171  *(PWCHAR)((PCHAR)BufferStart + FileNameLength) = UNICODE_NULL;
2172  }
2173 
2174  /* Now, does this file exist? */
2175  if (RtlDoesFileExists_UEx(NewBuffer, FALSE))
2176  {
2177  /* Call the full-path API to get the length */
2178  Length = RtlGetFullPathName_U(NewBuffer, Size, Buffer, PartName);
2179  break;
2180  }
2181 
2182  /* If we got here, path doesn't exist, so fail the call */
2183  Length = 0;
2184  if (!Path) break;
2185  }
2186 
2187  /* Free the allocation and return the length */
2188  RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
2189  return Length;
2190 }
2191 
2192 /*
2193  * @implemented
2194  */
2195 NTSTATUS
2196 NTAPI
2201  IN PSIZE_T FilePartSize,
2205 {
2206  NTSTATUS Status;
2207  PWCHAR StaticBuffer;
2208  PCWCH ShortName;
2209  ULONG Length;
2210  USHORT StaticLength;
2211  UNICODE_STRING TempDynamicString;
2212 
2213  /* Initialize all our locals */
2214  ShortName = NULL;
2215  StaticBuffer = NULL;
2216  TempDynamicString.Buffer = NULL;
2217 
2218  /* Initialize the input parameters */
2219  if (StringUsed) *StringUsed = NULL;
2220  if (LengthNeeded) *LengthNeeded = 0;
2221  if (FilePartSize) *FilePartSize = 0;
2222 
2223  /* Check for invalid parameters */
2224  if ((DynamicString) && !(StringUsed) && (StaticString))
2225  {
2226  return STATUS_INVALID_PARAMETER;
2227  }
2228 
2229  /* Check if we did not get an input string */
2230  if (!StaticString)
2231  {
2232  /* Allocate one */
2233  StaticLength = MAX_PATH * sizeof(WCHAR);
2234  StaticBuffer = RtlpAllocateStringMemory(MAX_PATH * sizeof(WCHAR), TAG_USTR);
2235  if (!StaticBuffer) return STATUS_NO_MEMORY;
2236  }
2237  else
2238  {
2239  /* Use the one we received */
2240  StaticBuffer = StaticString->Buffer;
2241  StaticLength = StaticString->MaximumLength;
2242  }
2243 
2244  /* Call the lower-level function */
2246  StaticLength,
2247  StaticBuffer,
2248  &ShortName,
2249  NameInvalid,
2250  PathType);
2251  DPRINT("Length: %u StaticBuffer: %S\n", Length, StaticBuffer);
2252  if (!Length)
2253  {
2254  /* Fail if it failed */
2255  DbgPrint("%s(%d) - RtlGetFullPathName_Ustr() returned 0\n",
2256  __FUNCTION__,
2257  __LINE__);
2259  goto Quickie;
2260  }
2261 
2262  /* Check if it fits inside our static string */
2263  if ((StaticString) && (Length < StaticLength))
2264  {
2265  /* Set the final length */
2267 
2268  /* Set the file part size */
2269  if (FilePartSize) *FilePartSize = ShortName ? (ShortName - StaticString->Buffer) : 0;
2270 
2271  /* Return the static string if requested */
2273 
2274  /* We are done with success */
2276  goto Quickie;
2277  }
2278 
2279  /* Did we not have an input dynamic string ?*/
2280  if (!DynamicString)
2281  {
2282  /* Return the length we need */
2284 
2285  /* And fail such that the caller can try again */
2287  goto Quickie;
2288  }
2289 
2290  /* Check if it fits in our static buffer */
2291  if ((StaticBuffer) && (Length < StaticLength))
2292  {
2293  /* NULL-terminate it */
2294  StaticBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2295 
2296  /* Set the settings for the dynamic string the caller sent */
2297  DynamicString->MaximumLength = StaticLength;
2299  DynamicString->Buffer = StaticBuffer;
2300 
2301  /* Set the part size */
2302  if (FilePartSize) *FilePartSize = ShortName ? (ShortName - StaticBuffer) : 0;
2303 
2304  /* Return the dynamic string if requested */
2306 
2307  /* Do not free the static buffer on exit, and return success */
2308  StaticBuffer = NULL;
2310  goto Quickie;
2311  }
2312 
2313  /* Now try again under the PEB lock */
2316  StaticLength,
2317  StaticBuffer,
2318  &ShortName,
2319  NameInvalid,
2320  PathType);
2321  if (!Length)
2322  {
2323  /* It failed */
2324  DbgPrint("%s line %d: RtlGetFullPathName_Ustr() returned 0\n",
2325  __FUNCTION__, __LINE__);
2327  goto Release;
2328  }
2329 
2330  /* Check if it fits inside our static string now */
2331  if ((StaticString) && (Length < StaticLength))
2332  {
2333  /* Set the final length */
2335 
2336  /* Set the file part size */
2337  if (FilePartSize) *FilePartSize = ShortName ? (ShortName - StaticString->Buffer) : 0;
2338 
2339  /* Return the static string if requested */
2341 
2342  /* We are done with success */
2344  goto Release;
2345  }
2346 
2347  /* Check if the path won't even fit in a real string */
2348  if ((Length + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES)
2349  {
2350  /* Name is way too long, fail */
2352  goto Release;
2353  }
2354 
2355  /* Allocate the string to hold the path name now */
2356  TempDynamicString.Buffer = RtlpAllocateStringMemory(Length + sizeof(WCHAR),
2357  TAG_USTR);
2358  if (!TempDynamicString.Buffer)
2359  {
2360  /* Out of memory, fail */
2362  goto Release;
2363  }
2364 
2365  /* Add space for a NULL terminator, and now check the full path */
2366  TempDynamicString.MaximumLength = (USHORT)Length + sizeof(UNICODE_NULL);
2368  Length,
2369  TempDynamicString.Buffer,
2370  &ShortName,
2371  NameInvalid,
2372  PathType);
2373  if (!Length)
2374  {
2375  /* Some path error, so fail out */
2376  DbgPrint("%s line %d: RtlGetFullPathName_Ustr() returned 0\n",
2377  __FUNCTION__, __LINE__);
2379  goto Release;
2380  }
2381 
2382  /* It should fit in the string we just allocated */
2383  ASSERT(Length < (TempDynamicString.MaximumLength - sizeof(WCHAR)));
2384  if (Length > TempDynamicString.MaximumLength)
2385  {
2386  /* This is really weird and would mean some kind of race */
2388  goto Release;
2389  }
2390 
2391  /* Return the file part size */
2392  if (FilePartSize) *FilePartSize = ShortName ? (ShortName - TempDynamicString.Buffer) : 0;
2393 
2394  /* Terminate the whole string now */
2395  TempDynamicString.Buffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2396 
2397  /* Finalize the string and return it to the user */
2398  DynamicString->Buffer = TempDynamicString.Buffer;
2400  DynamicString->MaximumLength = TempDynamicString.MaximumLength;
2402 
2403  /* Return success and make sure we don't free the buffer on exit */
2404  TempDynamicString.Buffer = NULL;
2406 
2407 Release:
2408  /* Release the PEB lock */
2410 
2411 Quickie:
2412  /* Free any buffers we should be freeing */
2413  DPRINT("Status: %lx %S %S\n", Status, StaticBuffer, TempDynamicString.Buffer);
2414  if ((StaticString) && (StaticBuffer) && (StaticBuffer != StaticString->Buffer))
2415  {
2416  RtlpFreeMemory(StaticBuffer, TAG_USTR);
2417  }
2418  if (TempDynamicString.Buffer)
2419  {
2420  RtlpFreeMemory(TempDynamicString.Buffer, TAG_USTR);
2421  }
2422 
2423  /* Print out any unusual errors */
2424  if ((NT_ERROR(Status)) &&
2426  {
2427  DbgPrint("RTL: %s - failing on filename %wZ with status %08lx\n",
2429  }
2430 
2431  /* Return, we're all done */
2432  return Status;
2433 }
2434 
2435 /*
2436  * @implemented
2437  */
2438 NTSTATUS
2439 NTAPI
2441  IN PUNICODE_STRING PathString,
2442  IN PUNICODE_STRING FileNameString,
2443  IN PUNICODE_STRING ExtensionString,
2444  IN PUNICODE_STRING CallerBuffer,
2446  OUT PUNICODE_STRING* FullNameOut OPTIONAL,
2447  OUT PSIZE_T FilePartSize OPTIONAL,
2449 {
2450  WCHAR StaticCandidateBuffer[MAX_PATH];
2451  UNICODE_STRING StaticCandidateString;
2452  NTSTATUS Status;
2454  PWCHAR p, End, CandidateEnd, SegmentEnd;
2455  SIZE_T SegmentSize, ByteCount, PathSize, MaxPathSize = 0;
2456  USHORT NamePlusExtLength, WorstCaseLength, ExtensionLength = 0;
2457  PUNICODE_STRING FullIsolatedPath;
2458  DPRINT("DOS Path Search: %lx %wZ %wZ %wZ %wZ %wZ\n",
2459  Flags, PathString, FileNameString, ExtensionString, CallerBuffer, DynamicString);
2460 
2461  /* Initialize the input string */
2462  RtlInitEmptyUnicodeString(&StaticCandidateString,
2463  StaticCandidateBuffer,
2464  sizeof(StaticCandidateBuffer));
2465 
2466  /* Initialize optional arguments */
2467  if (FullNameOut ) *FullNameOut = NULL;
2468  if (FilePartSize) *FilePartSize = 0;
2469  if (LengthNeeded) *LengthNeeded = 0;
2470  if (DynamicString)
2471  {
2474  }
2475 
2476  /* Check for invalid parameters */
2477  if ((Flags & ~7) ||
2478  !(PathString) ||
2479  !(FileNameString) ||
2480  ((CallerBuffer) && (DynamicString) && !(FullNameOut)))
2481  {
2482  /* Fail */
2483  DbgPrint("%s: Invalid parameters passed\n", __FUNCTION__);
2485  goto Quickie;
2486  }
2487 
2488  /* First check what kind of path this is */
2489  PathType = RtlDetermineDosPathNameType_Ustr(FileNameString);
2490 
2491  /* Check if the caller wants to prevent relative .\ and ..\ paths */
2492  if ((Flags & 2) &&
2494  (FileNameString->Length >= (2 * sizeof(WCHAR))) &&
2495  (FileNameString->Buffer[0] == L'.') &&
2496  ((IS_PATH_SEPARATOR(FileNameString->Buffer[1])) ||
2497  ((FileNameString->Buffer[1] == L'.') &&
2498  ((FileNameString->Length >= (3 * sizeof(WCHAR))) &&
2499  (IS_PATH_SEPARATOR(FileNameString->Buffer[2]))))))
2500  {
2501  /* Yes, and this path is like that, so make it seem unknown */
2503  }
2504 
2505  /* Now check relative vs non-relative paths */
2507  {
2508  /* Does the caller want SxS? */
2509  if (Flags & 1)
2510  {
2511  /* Apply the SxS magic */
2512  FullIsolatedPath = NULL;
2514  FileNameString,
2515  ExtensionString,
2516  CallerBuffer,
2517  DynamicString,
2518  &FullIsolatedPath,
2519  NULL,
2520  FilePartSize,
2521  LengthNeeded);
2522  if (NT_SUCCESS(Status))
2523  {
2524  /* We found the SxS path, return it */
2525  if (FullNameOut) *FullNameOut = FullIsolatedPath;
2526  goto Quickie;
2527  }
2528  else if (Status != STATUS_SXS_KEY_NOT_FOUND)
2529  {
2530  /* Critical SxS error, fail */
2531  DbgPrint("%s: Failing because call to "
2532  "RtlDosApplyIsolationRedirection_Ustr(%wZ) failed with "
2533  "status 0x%08lx\n",
2534  __FUNCTION__,
2535  FileNameString,
2536  Status);
2537  goto Quickie;
2538  }
2539  }
2540 
2541  /* No SxS key found, or not requested, check if there's an extension */
2542  if (ExtensionString)
2543  {
2544  /* Save the extension length, and check if there's a file name */
2545  ExtensionLength = ExtensionString->Length;
2546  if (FileNameString->Length)
2547  {
2548  /* Start parsing the file name */
2549  End = &FileNameString->Buffer[FileNameString->Length / sizeof(WCHAR)];
2550  while (End > FileNameString->Buffer)
2551  {
2552  /* If we find a path separator, there's no extension */
2553  if (IS_PATH_SEPARATOR(*--End)) break;
2554 
2555  /* Otherwise, did we find an extension dot? */
2556  if (*End == L'.')
2557  {
2558  /* Ignore what the caller sent it, use the filename's */
2559  ExtensionString = NULL;
2560  ExtensionLength = 0;
2561  break;
2562  }
2563  }
2564  }
2565  }
2566 
2567  /* Check if we got a path */
2568  if (PathString->Length)
2569  {
2570  /* Start parsing the path name, looking for path separators */
2571  End = &PathString->Buffer[PathString->Length / sizeof(WCHAR)];
2572  p = End;
2573  while ((p > PathString->Buffer) && (*--p == L';'))
2574  {
2575  /* This is the size of the path -- handle a trailing slash */
2576  PathSize = End - p - 1;
2577  if ((PathSize) && !(IS_PATH_SEPARATOR(*(End - 1)))) PathSize++;
2578 
2579  /* Check if we found a bigger path than before */
2580  if (PathSize > MaxPathSize) MaxPathSize = PathSize;
2581 
2582  /* Keep going with the path after this path separator */
2583  End = p;
2584  }
2585 
2586  /* This is the trailing path, run the same code as above */
2587  PathSize = End - p;
2588  if ((PathSize) && !(IS_PATH_SEPARATOR(*(End - 1)))) PathSize++;
2589  if (PathSize > MaxPathSize) MaxPathSize = PathSize;
2590 
2591  /* Finally, convert the largest path size into WCHAR */
2592  MaxPathSize *= sizeof(WCHAR);
2593  }
2594 
2595  /* Use the extension, the file name, and the largest path as the size */
2596  WorstCaseLength = ExtensionLength +
2597  FileNameString->Length +
2598  (USHORT)MaxPathSize +
2599  sizeof(UNICODE_NULL);
2600  if (WorstCaseLength > UNICODE_STRING_MAX_BYTES)
2601  {
2602  /* It has to fit in a registry string, if not, fail here */
2603  DbgPrint("%s returning STATUS_NAME_TOO_LONG because the computed "
2604  "worst case file name length is %Iu bytes\n",
2605  __FUNCTION__,
2606  WorstCaseLength);
2608  goto Quickie;
2609  }
2610 
2611  /* Scan the path now, to see if we can find the file */
2612  p = PathString->Buffer;
2613  End = &p[PathString->Length / sizeof(WCHAR)];
2614  while (p < End)
2615  {
2616  /* Find out where this path ends */
2617  for (SegmentEnd = p;
2618  ((SegmentEnd != End) && (*SegmentEnd != L';'));
2619  SegmentEnd++);
2620 
2621  /* Compute the size of this path */
2622  ByteCount = SegmentSize = (SegmentEnd - p) * sizeof(WCHAR);
2623 
2624  /* Handle trailing slash if there isn't one */
2625  if ((SegmentSize) && !(IS_PATH_SEPARATOR(*(SegmentEnd - 1))))
2626  {
2627  /* Add space for one */
2629  }
2630 
2631  /* Now check if our initial static buffer is too small */
2632  if (StaticCandidateString.MaximumLength <
2633  (SegmentSize + ExtensionLength + FileNameString->Length))
2634  {
2635  /* At this point we should've been using our static buffer */
2636  ASSERT(StaticCandidateString.Buffer == StaticCandidateBuffer);
2637  if (StaticCandidateString.Buffer != StaticCandidateBuffer)
2638  {
2639  /* Something is really messed up if this was the dynamic string */
2640  DbgPrint("%s: internal error #1; "
2641  "CandidateString.Buffer = %p; "
2642  "StaticCandidateBuffer = %p\n",
2643  __FUNCTION__,
2644  StaticCandidateString.Buffer,
2645  StaticCandidateBuffer);
2647  goto Quickie;
2648  }
2649 
2650  /* We checked before that the maximum possible size shoudl fit! */
2651  ASSERT((SegmentSize + FileNameString->Length + ExtensionLength) <
2653  if ((SegmentSize + ExtensionLength + FileNameString->Length) >
2654  (UNICODE_STRING_MAX_BYTES - sizeof(WCHAR)))
2655  {
2656  /* For some reason it's not fitting anymore. Something messed up */
2657  DbgPrint("%s: internal error #2; SegmentSize = %u, "
2658  "FileName->Length = %u, DefaultExtensionLength = %u\n",
2659  __FUNCTION__,
2660  SegmentSize,
2661  FileNameString->Length,
2662  ExtensionLength);
2664  goto Quickie;
2665  }
2666 
2667  /* Now allocate the dynamic string */
2668  StaticCandidateString.MaximumLength = FileNameString->Length +
2669  WorstCaseLength;
2670  StaticCandidateString.Buffer = RtlpAllocateStringMemory(WorstCaseLength,
2671  TAG_USTR);
2672  if (!StaticCandidateString.Buffer)
2673  {
2674  /* Out of memory, fail */
2675  DbgPrint("%s: Unable to allocate %u byte buffer for path candidate\n",
2676  __FUNCTION__,
2677  StaticCandidateString.MaximumLength);
2679  goto Quickie;
2680  }
2681  }
2682 
2683  /* Copy the path in the string */
2684  RtlCopyMemory(StaticCandidateString.Buffer, p, ByteCount);
2685 
2686  /* Get to the end of the string, and add the trailing slash if missing */
2687  CandidateEnd = &StaticCandidateString.Buffer[ByteCount / sizeof(WCHAR)];
2688  if ((SegmentSize) && (SegmentSize != ByteCount))
2689  {
2690  *CandidateEnd++ = OBJ_NAME_PATH_SEPARATOR;
2691  }
2692 
2693  /* Copy the filename now */
2694  RtlCopyMemory(CandidateEnd,
2695  FileNameString->Buffer,
2696  FileNameString->Length);
2697  CandidateEnd += (FileNameString->Length / sizeof(WCHAR));
2698 
2699  /* Check if there was an extension */
2700  if (ExtensionString)
2701  {
2702  /* Copy the extension too */
2703  RtlCopyMemory(CandidateEnd,
2704  ExtensionString->Buffer,
2705  ExtensionString->Length);
2706  CandidateEnd += (ExtensionString->Length / sizeof(WCHAR));
2707  }
2708 
2709  /* We are done, terminate it */
2710  *CandidateEnd = UNICODE_NULL;
2711 
2712  /* Now set the final length of the string so it becomes valid */
2713  StaticCandidateString.Length = (USHORT)(CandidateEnd -
2714  StaticCandidateString.Buffer) *
2715  sizeof(WCHAR);
2716 
2717  /* Check if this file exists */
2718  DPRINT("BUFFER: %S\n", StaticCandidateString.Buffer);
2719  if (RtlDoesFileExists_UEx(StaticCandidateString.Buffer, FALSE))
2720  {
2721  /* Awesome, it does, now get the full path */
2722  Status = RtlGetFullPathName_UstrEx(&StaticCandidateString,
2723  CallerBuffer,
2724  DynamicString,
2725  (PUNICODE_STRING*)FullNameOut,
2726  FilePartSize,
2727  NULL,
2728  &PathType,
2729  LengthNeeded);
2730  if (!(NT_SUCCESS(Status)) &&
2731  ((Status != STATUS_NO_SUCH_FILE) &&
2733  {
2734  DbgPrint("%s: Failing because we thought we found %wZ on "
2735  "the search path, but RtlGetfullPathNameUStrEx() "
2736  "returned %08lx\n",
2737  __FUNCTION__,
2738  &StaticCandidateString,
2739  Status);
2740  }
2741  DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
2742  goto Quickie;
2743  }
2744  else
2745  {
2746  /* Otherwise, move to the next path */
2747  if (SegmentEnd != End)
2748  {
2749  /* Handle the case of the path separator trailing */
2750  p = SegmentEnd + 1;
2751  }
2752  else
2753  {
2754  p = SegmentEnd;
2755  }
2756  }
2757  }
2758 
2759  /* Loop finished and we didn't break out -- fail */
2761  }
2762  else
2763  {
2764  /* We have a full path, so check if it does exist */
2765  DPRINT("%wZ\n", FileNameString);
2766  if (!RtlDoesFileExists_UstrEx(FileNameString, TRUE))
2767  {
2768  /* It doesn't exist, did we have an extension? */
2769  if (!(ExtensionString) || !(ExtensionString->Length))
2770  {
2771  /* No extension, so just fail */
2773  goto Quickie;
2774  }
2775 
2776  /* There was an extension, check if the filename already had one */
2777  if (!(Flags & 4) && (FileNameString->Length))
2778  {
2779  /* Parse the filename */
2780  p = FileNameString->Buffer;
2781  End = &p[FileNameString->Length / sizeof(WCHAR)];
2782  while (End > p)
2783  {
2784  /* If there's a path separator, there's no extension */
2785  if (IS_PATH_SEPARATOR(*--End)) break;
2786 
2787  /* Othwerwise, did we find an extension dot? */
2788  if (*End == L'.')
2789  {
2790  /* File already had an extension, so fail */
2792  goto Quickie;
2793  }
2794  }
2795  }
2796 
2797  /* So there is an extension, we'll try again by adding it */
2798  NamePlusExtLength = FileNameString->Length +
2799  ExtensionString->Length +
2800  sizeof(UNICODE_NULL);
2801  if (NamePlusExtLength > UNICODE_STRING_MAX_BYTES)
2802  {
2803  /* It won't fit in any kind of valid string, so fail */
2804  DbgPrint("%s: Failing because filename plus extension (%Iu bytes) is too big\n",
2805  __FUNCTION__,
2806  NamePlusExtLength);
2808  goto Quickie;
2809  }
2810 
2811  /* Fill it fit in our temporary string? */
2812  if (NamePlusExtLength > StaticCandidateString.MaximumLength)
2813  {
2814  /* It won't fit anymore, allocate a dynamic string for it */
2815  StaticCandidateString.MaximumLength = NamePlusExtLength;
2816  StaticCandidateString.Buffer = RtlpAllocateStringMemory(NamePlusExtLength,
2817  TAG_USTR);
2818  if (!StaticCandidateString.Buffer)
2819  {
2820  /* Ran out of memory, so fail */
2821  DbgPrint("%s: Failing because allocating the dynamic filename buffer failed\n",
2822  __FUNCTION__);
2824  goto Quickie;
2825  }
2826  }
2827 
2828  /* Copy the filename */
2829  RtlCopyUnicodeString(&StaticCandidateString, FileNameString);
2830 
2831  /* Copy the extension */
2832  RtlAppendUnicodeStringToString(&StaticCandidateString,
2833  ExtensionString);
2834 
2835  DPRINT("SB: %wZ\n", &StaticCandidateString);
2836 
2837  /* And check if this file now exists */
2838  if (!RtlDoesFileExists_UstrEx(&StaticCandidateString, TRUE))
2839  {
2840  /* Still no joy, fail out */
2842  goto Quickie;
2843  }
2844 
2845  /* File was found, get the final full path */
2846  Status = RtlGetFullPathName_UstrEx(&StaticCandidateString,
2847  CallerBuffer,
2848  DynamicString,
2849  (PUNICODE_STRING*)FullNameOut,
2850  FilePartSize,
2851  NULL,
2852  &PathType,
2853  LengthNeeded);
2854  if (!(NT_SUCCESS(Status)) && (Status != STATUS_NO_SUCH_FILE))
2855  {
2856  DbgPrint("%s: Failing on \"%wZ\" because RtlGetfullPathNameUStrEx() "
2857  "failed with status %08lx\n",
2858  __FUNCTION__,
2859  &StaticCandidateString,
2860  Status);
2861  }
2862  DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
2863  }
2864  else
2865  {
2866  /* File was found on the first try, get the final full path */
2867  Status = RtlGetFullPathName_UstrEx(FileNameString,
2868  CallerBuffer,
2869  DynamicString,
2870  (PUNICODE_STRING*)FullNameOut,
2871  FilePartSize,
2872  NULL,
2873  &PathType,
2874  LengthNeeded);
2875  if (!(NT_SUCCESS(Status)) &&
2876  ((Status != STATUS_NO_SUCH_FILE) &&
2878  {
2879  DbgPrint("%s: Failing because RtlGetfullPathNameUStrEx() on %wZ "
2880  "failed with status %08lx\n",
2881  __FUNCTION__,
2882  FileNameString,
2883  Status);
2884  }
2885  DPRINT("Status: %lx BUFFER: %S\n", Status, CallerBuffer->Buffer);
2886  }
2887  }
2888 
2889 Quickie:
2890  /* Anything that was not an error, turn into STATUS_SUCCESS */
2892 
2893  /* Check if we had a dynamic string */
2894  if ((StaticCandidateString.Buffer) &&
2895  (StaticCandidateString.Buffer != StaticCandidateBuffer))
2896  {
2897  /* Free it */
2898  RtlFreeUnicodeString(&StaticCandidateString);
2899  }
2900 
2901  /* Return the status */
2902  return Status;
2903 }
2904 
2905 /*
2906  * @implemented
2907  */
2908 BOOLEAN
2909 NTAPI
2911 {
2912  /* Call the new function */
2914 }
2915 
2916 /* EOF */
IN PDCB IN POEM_STRING IN PUNICODE_STRING IN OUT POEM_STRING ShortName
Definition: fatprocs.h:1294
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:2049
signed char * PCHAR
Definition: retypes.h:7
static IN ULONG IN PWSTR OUT PCWSTR OUT PBOOLEAN InvalidName
CONST WCHAR * PCWCH
Definition: ntbasedef.h:418
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:2197
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:1961
const uint16_t * PCWSTR
Definition: typedefs.h:55
#define IN
Definition: typedefs.h:38
ULONG NTAPI RtlGetLongestNtPathLength(VOID)
Definition: path.c:1436
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define max(a, b)
Definition: svc.c:63
#define TRUE
Definition: types.h:120
_In_ __drv_aliasesMem PSTRING Prefix
Definition: rtlfuncs.h:1631
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
static ULONG_PTR *static HANDLE(WINAPI *pCreateActCtxW)(PCACTCTXW)
Type
Definition: Type.h:6
const UNICODE_STRING RtlpDosCONDevice
Definition: path.c:45
_In_ BOOLEAN Release
Definition: classpnp.h:929
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:225
#define DbgPrint
Definition: loader.c:25
SIZE_T Size
Definition: rtltypes.h:1809
USHORT MaximumLength
Definition: env_spec_w32.h:370
VOID NTAPI RtlReleaseRelativeName(IN PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1415
NTSTATUS NTAPI RtlDosPathNameToRelativeNtPathName_U_WithStatus(IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1944
WCHAR CurrentDirectory[1024]
Definition: chkdsk.c:74
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:1036
const UNICODE_STRING RtlpDosAUXDevice
Definition: path.c:44
BOOLEAN NTAPI RtlDosPathNameToRelativeNtPathName_U(IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1925
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
C_ASSERT(RTL_CURDIR_ALL_FLAGS==OBJ_HANDLE_TAGBITS)
uint16_t * PWSTR
Definition: typedefs.h:54
#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:1375
#define RTL_UNCHANGED_DOS_PATH
Definition: rtlfuncs.h:2862
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:1823
const UNICODE_STRING RtlpDosSlashCONDevice
Definition: path.c:38
_In_ UINT Bytes
Definition: mmcopy.h:9
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:615
#define STATUS_SXS_KEY_NOT_FOUND
Definition: ntstatus.h:1170
VOID NTAPI RtlpFreeMemory(_In_ PVOID Mem, _In_ ULONG Tag)
Definition: rtlcompat.c:45
uint16_t * PWCHAR
Definition: typedefs.h:54
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
static USHORT PathLength
#define UNICODE_STRING_MAX_BYTES
#define IS_PATH_SEPARATOR(x)
Definition: path.c:24
#define FILE_SHARE_READ
Definition: compat.h:125
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
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:1907
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:64
static const UNICODE_STRING RtlpDefaultExtension
Definition: path.c:50
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define RTL_CONVERTED_UNC_PATH
Definition: rtlfuncs.h:2860
static ULONG_PTR
Definition: path.c:79
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:451
static IN ULONG IN PWSTR OUT PCWSTR OUT PBOOLEAN OUT PATH_TYPE_AND_UNKNOWN * PathType
ULONG NTAPI RtlGetFullPathName_U(_In_ PCWSTR FileName, _In_ ULONG Size, _Out_z_bytecap_(Size) PWSTR Buffer, _Out_opt_ PWSTR *ShortName)
Definition: path.c:1868
#define _Out_z_bytecap_(size)
Definition: no_sal2.h:385
#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
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define STATUS_NOT_A_DIRECTORY
Definition: udferr_usr.h:169
ULONG_PTR * PSIZE_T
Definition: typedefs.h:78
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 UNICODE_NULL
#define ANSI_NULL
_In_ ULONG BufferLength
Definition: usbdlib.h:225
#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:248
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:1268
NTSYSAPI NTSTATUS NTAPI RtlQueryEnvironmentVariable_U(_In_opt_ PWSTR Environment, _In_ PCUNICODE_STRING Name, _Out_ PUNICODE_STRING Value)
smooth NULL
Definition: ftsmooth.c:416
#define _Out_writes_bytes_(size)
Definition: no_sal2.h:370
_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:323
NTSTATUS NTAPI NtQueryVolumeInformationFile(IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FsInformation, IN ULONG Length, IN FS_INFORMATION_CLASS FsInformationClass)
Definition: iofunc.c:4084
void DPRINT(...)
Definition: polytest.cpp:61
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcsrchr(_In_z_ const wchar_t *_Str, _In_ wchar_t _Ch)
Definition: bufpool.h:45
BOOLEAN NTAPI RtlDoesFileExists_U(IN PCWSTR FileName)
Definition: path.c:2910
_Inout_ PRTL_BUFFER _In_ SIZE_T RequiredSize
NTSTATUS NTAPI RtlComputePrivatizedDllName_U(_In_ PUNICODE_STRING DllName, _Inout_ PUNICODE_STRING RealName, _Inout_ PUNICODE_STRING LocalName)
Definition: path.c:467
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:484
#define PCHAR
Definition: match.c:90
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
#define _Out_opt_
Definition: no_sal2.h:339
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
NTSTATUS NTAPI RtlSetCurrentDirectory_U(IN PUNICODE_STRING Path)
Definition: path.c:1620
__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
static const UNICODE_STRING RtlpPathDividers
Definition: path.c:52
#define OBJ_INHERIT
Definition: winternl.h:225
#define MAX_PATH
Definition: compat.h:26
const GLubyte * c
Definition: glext.h:8905
#define Len
Definition: deflate.h:82
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
BOOLEAN NTAPI RtlDoesFileExists_UStr(IN PUNICODE_STRING FileName)
Definition: path.c:1384
PPEB NTAPI RtlGetCurrentPeb(VOID)
Definition: libsupp.c:63
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define _Inout_
Definition: no_sal2.h:244
#define NT_ERROR(Status)
Definition: umtypes.h:106
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
Definition: partlist.h:33
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
ULONG NTAPI RtlGetCurrentDirectory_U(_In_ ULONG MaximumLength, _Out_bytecap_(MaximumLength) PWSTR Buffer)
Definition: path.c:1542
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#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:1295
#define RTL_CONVERTED_NT_PATH
Definition: rtlfuncs.h:2861
UNICODE_STRING ImagePathName
Definition: btrfs_drv.h:1805
static const WCHAR L[]
Definition: oid.c:1250
BOOLEAN NTAPI RtlDoesFileExists_UEx(IN PCWSTR FileName, IN BOOLEAN SucceedIfBusy)
Definition: path.c:1392
#define InterlockedDecrement
Definition: armddk.h:52
UNICODE_STRING String
Definition: rtltypes.h:1817
PRTL_USER_PROCESS_PARAMETERS ProcessParameters
Definition: btrfs_drv.h:1817
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:778
#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:893
RTL_PATH_TYPE NTAPI RtlDetermineDosPathNameType_U(IN PCWSTR Path)
Definition: path.c:1494
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:359
#define SYNCHRONIZE
Definition: nt_native.h:61
#define RTL_CURDIR_ALL_FLAGS
Definition: path.c:28
#define TAG_USTR
Definition: libsupp.c:111
_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:1061
Status
Definition: gdiplustypes.h:24
#define _In_
Definition: no_sal2.h:204
UnicodeString MaximumLength
Definition: rtlfuncs.h:2982
ULONG_PTR SIZE_T
Definition: typedefs.h:78
BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(IN PCWSTR DosName, OUT PUNICODE_STRING NtName, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:1889
struct _FileName FileName
Definition: fatprocs.h:884
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:20
unsigned short USHORT
Definition: pedump.c:61
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
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:1311
_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:2859
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
NTSYSAPI NTSTATUS WINAPI RtlInitUnicodeStringEx(PUNICODE_STRING, PCWSTR)
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:715
VOID NTAPI RtlAcquirePebLock(VOID)
Definition: libsupp.c:72
#define RTL_CURDIR_IS_REMOVABLE
Definition: path.c:26
#define _Out_bytecap_(size)
Definition: no_sal2.h:325
#define DPRINT1
Definition: precomp.h:8
UNICODE_STRING DosPath
Definition: rtltypes.h:1362
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
WCHAR FileNameBuffer[_MAX_PATH]
Definition: framewnd.c:239
NTSTATUS NTAPI RtlpApplyLengthFunction(IN ULONG Flags, IN ULONG Type, IN PVOID UnicodeStringOrUnicodeStringBuffer, IN PVOID LengthFunction)
Definition: path.c:446
#define OUT
Definition: typedefs.h:39
PUCHAR Buffer
Definition: rtltypes.h:1807
NTSTATUS NTAPI RtlpWin32NTNameToNtPathName_U(IN PUNICODE_STRING DosPath, OUT PUNICODE_STRING NtPath, OUT PCWSTR *PartName, OUT PRTL_RELATIVE_NAME_U RelativeName)
Definition: path.c:962
NTSYSAPI NTSTATUS NTAPI RtlFindCharInUnicodeString(_In_ ULONG Flags, _In_ PCUNICODE_STRING SearchString, _In_ PCUNICODE_STRING MatchString, _Out_ PUSHORT Position)
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:246
unsigned int ULONG
Definition: retypes.h:1
HANDLE Handle
Definition: rtltypes.h:1363
#define UNIMPLEMENTED
Definition: debug.h:114
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
PRTLP_CURDIR_REF RtlpCurDirRef
Definition: path.c:55
_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:1374
_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
#define RTL_USER_PROCESS_PARAMETERS_NORMALIZED
Definition: rtltypes.h:41
NTSTATUS NTAPI RtlGetLengthWithoutTrailingPathSeparators(IN ULONG Flags, IN PCUNICODE_STRING PathString, OUT PULONG Length)
Definition: path.c:1454
GLfloat GLfloat p
Definition: glext.h:8902
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
const UNICODE_STRING RtlpDosDevicesUncPrefix
Definition: path.c:36
return STATUS_SUCCESS
Definition: btrfs.c:2966
#define __FUNCTION__
Definition: types.h:112
static SERVICE_STATUS status
Definition: service.c:31
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
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
IN PUNICODE_STRING StaticString
NTSTATUS NTAPI RtlGetLengthWithoutLastFullDosOrNtPathElement(IN ULONG Flags, IN PWCHAR Path, OUT PULONG LengthOut)
Definition: path.c:457
ULONG NTAPI RtlIsDosDeviceName_U(IN PCWSTR Path)
Definition: path.c:1520
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:2440
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