ReactOS  0.4.12-dev-712-ge6be187
path.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Win32 Base API
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: dll/win32/kernel32/client/path.c
5  * PURPOSE: Handles path APIs
6  * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <k32.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
19 
22 
25 
26 /* This is bitmask for each illegal filename character */
27 /* If someone has time, please feel free to use 0b notation */
29 {
30  0xFFFFFFFF, // None allowed (00 to 1F)
31  0xFC009C05, // 20, 22, 2A, 2B, 2C, 2F, 3A, 3B, 3C, 3D, 3E, 3F not allowed
32  0x38000000, // 5B, 5C, 5D not allowed
33  0x10000000 // 7C not allowed
34 };
35 
37 {
38  {
44  },
45  {
51  }
52 };
53 
55 {
61 };
62 
64 {
70 };
71 
73 {
79 };
80 
82 
84 
85 /* PRIVATE FUNCTIONS **********************************************************/
86 
87 PWCHAR
88 WINAPI
90 {
91  PWCHAR FileNameEnd, FileNameSeparator;
92 
93  /* Find the first slash */
94  FileNameSeparator = wcschr(FileName, OBJ_NAME_PATH_SEPARATOR);
95  if (FileNameSeparator)
96  {
97  /* Find the last one */
98  FileNameEnd = wcsrchr(FileNameSeparator, OBJ_NAME_PATH_SEPARATOR);
99  ASSERT(FileNameEnd);
100 
101  /* Handle the case where they are one and the same */
102  if (FileNameEnd == FileNameSeparator) FileNameEnd++;
103  }
104  else
105  {
106  /* No directory was specified */
107  FileNameEnd = NULL;
108  }
109 
110  /* Return where the directory ends and the filename starts */
111  return FileNameEnd;
112 }
113 
114 LPWSTR
115 WINAPI
117  IN LPWSTR AppName,
119 {
120  PWCHAR PathBuffer, Buffer, AppNameEnd, PathCurrent;
121  SIZE_T PathLengthInBytes;
123  UNICODE_STRING EnvPath;
125 
126  /* Initialize state */
127  AppNameEnd = Buffer = PathBuffer = NULL;
129  PathLengthInBytes = 0;
130 
131  /* Loop the ordering array */
132  for (Order = PathOrder; *Order != BaseSearchPathInvalid; Order++) {
133  switch (*Order)
134  {
135  /* Compute the size of the DLL path */
136  case BaseSearchPathDll:
137 
138  /* This path only gets called if SetDllDirectory was called */
140 
141  /* Make sure there's a DLL directory size */
143  {
144  /* Add it, plus the separator */
145  PathLengthInBytes += BaseDllDirectory.Length + sizeof(L';');
146  }
147  break;
148 
149  /* Compute the size of the current path */
151 
152  /* Add ".;" */
153  PathLengthInBytes += (2 * sizeof(WCHAR));
154  break;
155 
156  /* Compute the size of the "PATH" environment variable */
157  case BaseSearchPathEnv:
158 
159  /* Grab PEB lock if one wasn't passed in */
161 
162  /* Query the size first */
163  EnvPath.MaximumLength = 0;
166  &EnvPath);
168  {
169  /* Compute the size we'll need for the environment */
170  EnvPath.MaximumLength = EnvPath.Length + sizeof(WCHAR);
171  if ((EnvPath.Length + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES)
172  {
173  /* Don't let it overflow */
174  EnvPath.MaximumLength = EnvPath.Length;
175  }
176 
177  /* Allocate the environment buffer */
178  Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
179  0,
180  EnvPath.MaximumLength);
181  if (Buffer)
182  {
183  /* Now query the PATH environment variable */
184  EnvPath.Buffer = Buffer;
187  &EnvPath);
188  }
189  else
190  {
191  /* Failure case */
193  }
194  }
195 
196  /* Release the PEB lock from above */
198 
199  /* There might not be a PATH */
201  {
202  /* In this case, skip this PathOrder */
203  EnvPath.Length = EnvPath.MaximumLength = 0;
205  }
206  else if (!NT_SUCCESS(Status))
207  {
208  /* An early failure, go to exit code */
209  goto Quickie;
210  }
211  else
212  {
213  /* Add the length of the PATH variable unless it's empty */
214  ASSERT(!(EnvPath.Length & 1));
215  if (EnvPath.Length)
216  {
217  /* Reserve space for the variable and a semicolon */
218  PathLengthInBytes += (EnvPath.Length + sizeof(L';'));
219  }
220  }
221  break;
222 
223  /* Compute the size of the default search path */
225 
226  /* Just add it... it already has a ';' at the end */
227  ASSERT(!(BaseDefaultPath.Length & 1));
228  PathLengthInBytes += BaseDefaultPath.Length;
229  break;
230 
231  /* Compute the size of the current app directory */
232  case BaseSearchPathApp:
233  /* Find out where the app name ends, to get only the directory */
234  if (AppName) AppNameEnd = BasepEndOfDirName(AppName);
235 
236  /* Check if there was no application name passed in */
237  if (!(AppName) || !(AppNameEnd))
238  {
239  /* Do we have a per-thread CURDIR to use? */
240  if (NtCurrentTeb()->NtTib.SubSystemTib)
241  {
242  /* This means someone added RTL_PERTHREAD_CURDIR */
244  }
245 
246  /* We do not. Do we have the LDR_ENTRY for the executable? */
247  if (!BasepExeLdrEntry)
248  {
249  /* We do not. Grab it */
252  NtCurrentPeb()->ImageBaseAddress);
253  }
254 
255  /* Now do we have it? */
256  if (BasepExeLdrEntry)
257  {
258  /* Yes, so read the name out of it */
260  }
261 
262  /* Find out where the app name ends, to get only the directory */
263  if (AppName) AppNameEnd = BasepEndOfDirName(AppName);
264  }
265 
266  /* So, do we have an application name and its directory? */
267  if ((AppName) && (AppNameEnd))
268  {
269  /* Add the size of the app's directory, plus the separator */
270  PathLengthInBytes += ((AppNameEnd - AppName) * sizeof(WCHAR)) + sizeof(L';');
271  }
272  break;
273 
274  default:
275  break;
276  }
277  }
278 
279  /* Bam, all done, we now have the final path size */
280  ASSERT(PathLengthInBytes > 0);
281  ASSERT(!(PathLengthInBytes & 1));
282 
283  /* Allocate the buffer to hold it */
284  PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLengthInBytes);
285  if (!PathBuffer)
286  {
287  /* Failure path */
289  goto Quickie;
290  }
291 
292  /* Now we loop again, this time to copy the data */
293  PathCurrent = PathBuffer;
294  for (Order = PathOrder; *Order != BaseSearchPathInvalid; Order++) {
295  switch (*Order)
296  {
297  /* Add the DLL path */
298  case BaseSearchPathDll:
300  {
301  /* Copy it in the buffer, ASSERT there's enough space */
302  ASSERT((((PathCurrent - PathBuffer + 1) * sizeof(WCHAR)) + BaseDllDirectory.Length) <= PathLengthInBytes);
303  RtlCopyMemory(PathCurrent,
306 
307  /* Update the current pointer, add a separator */
308  PathCurrent += (BaseDllDirectory.Length / sizeof(WCHAR));
309  *PathCurrent++ = ';';
310  }
311  break;
312 
313  /* Add the current application path */
314  case BaseSearchPathApp:
315  if ((AppName) && (AppNameEnd))
316  {
317  /* Copy it in the buffer, ASSERT there's enough space */
318  ASSERT(((PathCurrent - PathBuffer + 1 + (AppNameEnd - AppName)) * sizeof(WCHAR)) <= PathLengthInBytes);
319  RtlCopyMemory(PathCurrent,
320  AppName,
321  (AppNameEnd - AppName) * sizeof(WCHAR));
322 
323  /* Update the current pointer, add a separator */
324  PathCurrent += AppNameEnd - AppName;
325  *PathCurrent++ = ';';
326  }
327  break;
328 
329  /* Add the default search path */
331  /* Copy it in the buffer, ASSERT there's enough space */
332  ASSERT((((PathCurrent - PathBuffer) * sizeof(WCHAR)) + BaseDefaultPath.Length) <= PathLengthInBytes);
334 
335  /* Update the current pointer. The default path already has a ";" */
336  PathCurrent += (BaseDefaultPath.Length / sizeof(WCHAR));
337  break;
338 
339  /* Add the path in the PATH environment variable */
340  case BaseSearchPathEnv:
341  if (EnvPath.Length)
342  {
343  /* Copy it in the buffer, ASSERT there's enough space */
344  ASSERT((((PathCurrent - PathBuffer + 1) * sizeof(WCHAR)) + EnvPath.Length) <= PathLengthInBytes);
345  RtlCopyMemory(PathCurrent, EnvPath.Buffer, EnvPath.Length);
346 
347  /* Update the current pointer, add a separator */
348  PathCurrent += (EnvPath.Length / sizeof(WCHAR));
349  *PathCurrent++ = ';';
350  }
351  break;
352 
353  /* Add the current directory */
355 
356  /* Copy it in the buffer, ASSERT there's enough space */
357  ASSERT(((PathCurrent - PathBuffer + 2) * sizeof(WCHAR)) <= PathLengthInBytes);
358  *PathCurrent++ = '.';
359 
360  /* Add the path separator */
361  *PathCurrent++ = ';';
362  break;
363 
364  default:
365  break;
366  }
367  }
368 
369  /* Everything should've perfectly fit in there */
370  ASSERT((PathCurrent - PathBuffer) * sizeof(WCHAR) == PathLengthInBytes);
371  ASSERT(PathCurrent > PathBuffer);
372 
373  /* Terminate the whole thing */
374  PathCurrent[-1] = UNICODE_NULL;
375 
376 Quickie:
377  /* Exit path: free our buffers */
378  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
379  if (PathBuffer)
380  {
381  /* This only gets freed in the failure path, since caller wants it */
382  if (!NT_SUCCESS(Status))
383  {
384  RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
385  PathBuffer = NULL;
386  }
387  }
388 
389  /* Return the path! */
390  return PathBuffer;
391 }
392 
393 LPWSTR
394 WINAPI
396 {
397  DPRINT("Computing Process Search path\n");
398 
399  /* Compute the path using default process order */
401 }
402 
403 LPWSTR
404 WINAPI
406 {
407  PBASE_SEARCH_PATH_TYPE PathOrder;
408  DPRINT("Computing EXE path: %S\n", FullPath);
409 
410  /* Check if we should use the current directory */
411  PathOrder = NeedCurrentDirectoryForExePathW(FullPath) ?
413 
414  /* And now compute the path */
415  return BasepComputeProcessPath(PathOrder, NULL, NULL);
416 }
417 
418 LPWSTR
419 WINAPI
422 {
423  LPWSTR DllPath = NULL;
424  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager");
425  UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SafeDllSearchMode");
427  KEY_VALUE_PARTIAL_INFORMATION PartialInfo;
431  BASE_CURRENT_DIR_PLACEMENT CurrentDirPlacement, OldCurrentDirPlacement;
432 
433  /* Acquire DLL directory lock */
435 
436  /* Check if we have a base dll directory */
438  {
439  /* Then compute the process path using DLL order (without curdir) */
441 
442  /* Release DLL directory lock */
444 
445  /* Return dll path */
446  return DllPath;
447  }
448 
449  /* Release DLL directory lock */
451 
452  /* Read the current placement */
453  CurrentDirPlacement = BasepDllCurrentDirPlacement;
454  if (CurrentDirPlacement == BaseCurrentDirPlacementInvalid)
455  {
456  /* Open the configuration key */
458  if (NT_SUCCESS(Status))
459  {
460  /* Query if safe search is enabled */
462  &ValueName,
464  &PartialInfo,
465  sizeof(PartialInfo),
466  &ResultLength);
467  if (NT_SUCCESS(Status))
468  {
469  /* Read the value if the size is OK */
470  if (ResultLength == sizeof(PartialInfo))
471  {
472  CurrentDirPlacement = *(PULONG)PartialInfo.Data;
473  }
474  }
475 
476  /* Close the handle */
478 
479  /* Validate the registry value */
480  if ((CurrentDirPlacement <= BaseCurrentDirPlacementInvalid) ||
481  (CurrentDirPlacement >= BaseCurrentDirPlacementMax))
482  {
483  /* Default to safe search */
484  CurrentDirPlacement = BaseCurrentDirPlacementSafe;
485  }
486  }
487 
488  /* Update the placement and read the old one */
490  CurrentDirPlacement,
492  if (OldCurrentDirPlacement != BaseCurrentDirPlacementInvalid)
493  {
494  /* If there already was a placement, use it */
495  CurrentDirPlacement = OldCurrentDirPlacement;
496  }
497  }
498 
499  /* Check if the placement is invalid or not set */
500  if ((CurrentDirPlacement <= BaseCurrentDirPlacementInvalid) ||
501  (CurrentDirPlacement >= BaseCurrentDirPlacementMax))
502  {
503  /* Default to safe search */
504  CurrentDirPlacement = BaseCurrentDirPlacementSafe;
505  }
506 
507  /* Compute the process path using either normal or safe search */
508  DllPath = BasepComputeProcessPath(BaseDllOrderCurrent[CurrentDirPlacement],
509  FullPath,
510  Environment);
511 
512  /* Return dll path */
513  return DllPath;
514 }
515 
516 BOOLEAN
517 WINAPI
519 {
520  PUNICODE_STRING CurDir;
521  USHORT CurLength;
522  BOOLEAN Result;
523  UNICODE_STRING CurDirCopy;
524 
525  CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath;
526 
527  CurLength = CurDir->Length;
528  if (CurDir->Length <= 6)
529  {
530  if (CurLength != DirName->Length) return FALSE;
531  }
532  else
533  {
534  if ((CurLength - 2) != DirName->Length) return FALSE;
535  }
536 
538 
539  CurDirCopy = *CurDir;
540  if (CurDirCopy.Length > 6) CurDirCopy.Length -= 2;
541 
542  Result = 0;
543 
544  if (RtlEqualUnicodeString(&CurDirCopy, DirName, TRUE)) Result = TRUE;
545 
547 
548  return Result;
549 }
550 
551 /*
552  * Why not use RtlIsNameLegalDOS8Dot3? In fact the actual algorithm body is
553  * identical (other than the Rtl can optionally check for spaces), however the
554  * Rtl will always convert to OEM, while kernel32 has two possible file modes
555  * (ANSI or OEM). Therefore we must duplicate the algorithm body to get
556  * the correct compatible results
557  */
558 BOOL
559 WINAPI
561  IN ULONG Length)
562 {
563  BOOLEAN HasExtension;
564  UCHAR c;
567  ANSI_STRING AnsiName;
568  ULONG i, Dots;
570  ASSERT(Name);
571 
572  /* What do you think 8.3 means? */
573  if (Length > 12) return FALSE;
574 
575  /* Sure, any empty name is a short name */
576  if (!Length) return TRUE;
577 
578  /* This could be . or .. or something else */
579  if (*Name == L'.')
580  {
581  /* Which one is it */
582  if ((Length == 1) || ((Length == 2) && *(Name + 1) == L'.'))
583  {
584  /* . or .., this is good */
585  return TRUE;
586  }
587 
588  /* Some other bizare dot-based name, not good */
589  return FALSE;
590  }
591 
592  /* Initialize our two strings */
593  RtlInitEmptyAnsiString(&AnsiName, AnsiBuffer, MAX_PATH);
594  RtlInitEmptyUnicodeString(&UnicodeName, Name, (USHORT)Length * sizeof(WCHAR));
595  UnicodeName.Length = UnicodeName.MaximumLength;
596 
597  /* Now do the conversion */
599  if (!NT_SUCCESS(Status)) return FALSE;
600 
601  /* Now we loop the name */
602  HasExtension = FALSE;
603  for (i = 0, Dots = Length - 1; i < AnsiName.Length; i++, Dots--)
604  {
605  /* Read the current byte */
606  c = AnsiName.Buffer[i];
607 
608  /* Is it DBCS? */
609  if (IsDBCSLeadByte(c))
610  {
611  /* If we're near the end of the string, we can't allow a DBCS */
612  if ((!(HasExtension) && (i >= 7)) || (i == AnsiName.Length - 1))
613  {
614  return FALSE;
615  }
616 
617  /* Otherwise we skip over it */
618  continue;
619  }
620 
621  /* Check for illegal characters */
622  if ((c > 0x7F) || (IllegalMask[c / 32] & (1 << (c % 32))))
623  {
624  return FALSE;
625  }
626 
627  /* Check if this is perhaps an extension? */
628  if (c == '.')
629  {
630  /* Unless the extension is too large or there's more than one */
631  if ((HasExtension) || (Dots > 3)) return FALSE;
632 
633  /* This looks like an extension */
634  HasExtension = TRUE;
635  }
636 
637  /* 8.3 length was validated, but now we must guard against 9.2 or similar */
638  if ((i >= 8) && !(HasExtension)) return FALSE;
639  }
640 
641  /* You survived the loop, this is a good short name */
642  return TRUE;
643 }
644 
645 BOOL
646 WINAPI
648  IN ULONG Length)
649 {
650  BOOLEAN HasExtension;
651  ULONG i, Dots;
652 
653  /* More than 8.3, any combination of dots, and NULL names are all long */
654  if (!(Length) || (Length > 12) || (*FileName == L'.')) return TRUE;
655 
656  /* Otherwise, initialize our scanning loop */
657  HasExtension = FALSE;
658  for (i = 0, Dots = Length - 1; i < Length; i++, Dots--)
659  {
660  /* Check if this could be an extension */
661  if (FileName[i] == L'.')
662  {
663  /* Unlike the short case, we WANT more than one extension, or a long one */
664  if ((HasExtension) || (Dots > 3))
665  {
666  return TRUE;
667  }
668  HasExtension = TRUE;
669  }
670 
671  /* Check if this would violate the "8" in 8.3, ie. 9.2 */
672  if ((i >= 8) && (!HasExtension)) return TRUE;
673  }
674 
675  /* The name *seems* to conform to 8.3 */
676  return FALSE;
677 }
678 
679 BOOL
680 WINAPI
682  OUT PWCHAR *First,
683  OUT PWCHAR *Last,
684  IN BOOL UseShort)
685 {
686  PWCHAR p;
687  ULONG Length;
688  BOOL Found = 0;
689  ASSERT(Path);
690 
691  /* Loop while there is something in the path */
692  while (TRUE)
693  {
694  /* Loop within the path skipping slashes */
695  while ((*Path == L'\\') || (*Path == L'/')) Path++;
696 
697  /* Make sure there's something after the slashes too! */
698  if (*Path == UNICODE_NULL) break;
699 
700  /* Now skip past the file name until we get to the first slash */
701  p = Path + 1;
702  while ((*p) && ((*p != L'\\') && (*p != L'/'))) p++;
703 
704  /* Whatever is in between those two is now the file name length */
705  Length = p - Path;
706 
707  /*
708  * Check if it is valid
709  * Note that !IsShortName != IsLongName, these two functions simply help
710  * us determine if a conversion is necessary or not.
711  * "Found" really means: "Is a conversion necessary?", hence the "!"
712  */
713  Found = UseShort ? !IsShortName_U(Path, Length) : !IsLongName_U(Path, Length);
714  if (Found)
715  {
716  /* It is! did the caller request to know the markers? */
717  if ((First) && (Last))
718  {
719  /* Return them */
720  *First = Path;
721  *Last = p;
722  }
723  break;
724  }
725 
726  /* Is there anything else following this sub-path/filename? */
727  if (*p == UNICODE_NULL) break;
728 
729  /* Yes, keep going */
730  Path = p + 1;
731  }
732 
733  /* Return if anything was found and valid */
734  return Found;
735 }
736 
737 PWCHAR
738 WINAPI
740 {
741  PWCHAR ReturnPath;
742  ULONG i;
743 
744  /* Check what kind of path this is and how many slashes to skip */
746  {
749  {
750  /* Keep going until we bypass the path indicators */
751  for (ReturnPath = Path + 2, i = 2; (i > 0) && (*ReturnPath); ReturnPath++)
752  {
753  /* We look for 2 slashes, so keep at it until we find them */
754  if ((*ReturnPath == L'\\') || (*ReturnPath == L'/')) i--;
755  }
756 
757  return ReturnPath;
758  }
759 
761  return Path + 3;
762 
764  return Path + 2;
765 
766  case RtlPathTypeRooted:
767  return Path + 1;
768 
769  case RtlPathTypeRelative:
770  return Path;
771 
773  default:
774  return NULL;
775  }
776 }
777 
778 BOOL
779 WINAPI
781 {
783  UNICODE_STRING EmptyString;
784 
785  RtlInitEmptyUnicodeString(&EmptyString, NULL, 0);
788  &EmptyString);
790 }
791 
792 /* PUBLIC FUNCTIONS ***********************************************************/
793 
794 /*
795  * @implemented
796  */
797 BOOL
798 WINAPI
800 {
801  UNICODE_STRING OldDirectory, DllDirectory;
802 
803  if (lpPathName)
804  {
805  if (wcschr(lpPathName, L';'))
806  {
808  return FALSE;
809  }
810  if (!RtlCreateUnicodeString(&DllDirectory, lpPathName))
811  {
813  return FALSE;
814  }
815  }
816  else
817  {
818  RtlInitUnicodeString(&DllDirectory, NULL);
819  }
820 
822 
823  OldDirectory = BaseDllDirectory;
824  BaseDllDirectory = DllDirectory;
825 
827 
828  RtlFreeUnicodeString(&OldDirectory);
829  return TRUE;
830 }
831 
832 /*
833  * @implemented
834  */
835 BOOL
836 WINAPI
838 {
839  ANSI_STRING AnsiDllDirectory;
840  UNICODE_STRING OldDirectory, DllDirectory;
842 
843  if (lpPathName)
844  {
845  if (strchr(lpPathName, ';'))
846  {
848  return FALSE;
849  }
850 
851  Status = RtlInitAnsiStringEx(&AnsiDllDirectory, lpPathName);
852  if (NT_SUCCESS(Status))
853  {
854  Status = Basep8BitStringToUnicodeString(&DllDirectory,
855  &AnsiDllDirectory,
856  TRUE);
857  }
858 
859  if (!NT_SUCCESS(Status))
860  {
862  return FALSE;
863  }
864  }
865  else
866  {
867  RtlInitUnicodeString(&DllDirectory, NULL);
868  }
869 
871 
872  OldDirectory = BaseDllDirectory;
873  BaseDllDirectory = DllDirectory;
874 
876 
877  RtlFreeUnicodeString(&OldDirectory);
878  return TRUE;
879 }
880 
881 /*
882  * @implemented
883  */
884 DWORD
885 WINAPI
888 {
889  ULONG Length;
890 
892 
893  if ((nBufferLength * sizeof(WCHAR)) > BaseDllDirectory.Length)
894  {
896  Length = BaseDllDirectory.Length / sizeof(WCHAR);
898  }
899  else
900  {
901  Length = (BaseDllDirectory.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR);
903  }
904 
906  return Length;
907 }
908 
909 /*
910  * @implemented
911  */
912 DWORD
913 WINAPI
916 {
918  ANSI_STRING AnsiDllDirectory;
919  ULONG Length;
920 
921  RtlInitEmptyAnsiString(&AnsiDllDirectory, lpBuffer, (USHORT)nBufferLength);
922 
924 
926  if (Length > nBufferLength)
927  {
929  if (lpBuffer) *lpBuffer = ANSI_NULL;
930  }
931  else
932  {
933  --Length;
934  Status = BasepUnicodeStringTo8BitString(&AnsiDllDirectory,
936  FALSE);
937  }
938 
940 
941  if (!NT_SUCCESS(Status))
942  {
944  Length = 0;
945  if (lpBuffer) *lpBuffer = ANSI_NULL;
946  }
947 
948  return Length;
949 }
950 
951 /*
952  * @implemented
953  */
954 BOOL
955 WINAPI
957 {
958  if (wcschr(ExeName, L'\\')) return TRUE;
959 
961 }
962 
963 /*
964  * @implemented
965  */
966 BOOL
967 WINAPI
969 {
970  if (strchr(ExeName, '\\')) return TRUE;
971 
973 }
974 
975 /*
976  * @implemented
977  *
978  * NOTE: Many of these A functions may seem to do rather complex A<->W mapping
979  * beyond what you would usually expect. There are two main reasons:
980  *
981  * First, these APIs are subject to the ANSI/OEM File API selection status that
982  * the caller has chosen, so we must use the "8BitString" internal Base APIs.
983  *
984  * Secondly, the Wide APIs (coming from the 9x world) are coded to return the
985  * length of the paths in "ANSI" by dividing their internal Wide character count
986  * by two... this is usually correct when dealing with pure-ASCII codepages but
987  * not necessarily when dealing with MBCS pre-Unicode sets, which NT supports
988  * for CJK, for example.
989  */
990 DWORD
991 WINAPI
996 {
998  PWCHAR Buffer = NULL;
999  ULONG PathSize, FilePartSize;
1001  UNICODE_STRING FileNameString, UniString;
1002  PWCHAR LocalFilePart;
1003  PWCHAR* FilePart;
1004 
1005  /* If the caller wants filepart, use a local wide buffer since this is A */
1006  FilePart = lpFilePart != NULL ? &LocalFilePart : NULL;
1007 
1008  /* Initialize for Quickie */
1009  FilePartSize = PathSize = 0;
1010  FileNameString.Buffer = NULL;
1011 
1012  /* First get our string in Unicode */
1014  if (!NT_SUCCESS(Status)) goto Quickie;
1015 
1016  /* Allocate a buffer to hold teh path name */
1017  Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
1018  0,
1019  MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1020  if (!Buffer)
1021  {
1023  goto Quickie;
1024  }
1025 
1026  /* Call into RTL to get the full Unicode path name */
1027  PathSize = RtlGetFullPathName_U(FileNameString.Buffer,
1028  MAX_PATH * sizeof(WCHAR),
1029  Buffer,
1030  FilePart);
1031  if (PathSize <= (MAX_PATH * sizeof(WCHAR)))
1032  {
1033  /* The buffer will fit, get the real ANSI string size now */
1034  Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize);
1035  if (NT_SUCCESS(Status))
1036  {
1037  /* Now check if the user wanted file part size as well */
1038  if ((PathSize) && (lpFilePart) && (LocalFilePart))
1039  {
1040  /* Yep, so in this case get the length of the file part too */
1041  Status = RtlUnicodeToMultiByteSize(&FilePartSize,
1042  Buffer,
1043  (ULONG)(LocalFilePart - Buffer) *
1044  sizeof(WCHAR));
1045  if (!NT_SUCCESS(Status))
1046  {
1047  /* We failed to do that, so fail the whole call */
1049  PathSize = 0;
1050  }
1051  }
1052  }
1053  }
1054  else
1055  {
1056  /* Reset the path size since the buffer is not large enough */
1057  PathSize = 0;
1058  }
1059 
1060  /* Either no path, or local buffer was too small, enter failure code */
1061  if (!PathSize) goto Quickie;
1062 
1063  /* If the *caller's* buffer was too small, fail, but add in space for NULL */
1064  if (PathSize >= nBufferLength)
1065  {
1066  PathSize++;
1067  goto Quickie;
1068  }
1069 
1070  /* So far so good, initialize a unicode string to convert back to ANSI/OEM */
1071  RtlInitUnicodeString(&UniString, Buffer);
1073  if (!NT_SUCCESS(Status))
1074  {
1075  /* Final conversion failed, fail the call */
1077  PathSize = 0;
1078  }
1079  else
1080  {
1081  /* Conversion worked, now copy the ANSI/OEM buffer into the buffer */
1082  RtlCopyMemory(lpBuffer, AnsiString.Buffer, PathSize + 1);
1084 
1085  /* And finally, did the caller request file part information? */
1086  if (lpFilePart)
1087  {
1088  /* Use the size we computed earlier and add it to the buffer */
1089  *lpFilePart = LocalFilePart ? &lpBuffer[FilePartSize] : 0;
1090  }
1091  }
1092 
1093 Quickie:
1094  /* Cleanup and return the path size */
1095  if (FileNameString.Buffer) RtlFreeUnicodeString(&FileNameString);
1096  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1097  return PathSize;
1098 }
1099 
1100 /*
1101  * @implemented
1102  */
1103 DWORD
1104 WINAPI
1109 {
1110  /* Call Rtl to do the work */
1112  nBufferLength * sizeof(WCHAR),
1113  lpBuffer,
1114  lpFilePart) / sizeof(WCHAR);
1115 }
1116 
1117 /*
1118  * @implemented
1119  */
1120 DWORD
1121 WINAPI
1126  OUT LPSTR lpBuffer,
1128 {
1129  PUNICODE_STRING FileNameString;
1130  UNICODE_STRING PathString, ExtensionString;
1131  NTSTATUS Status;
1132  ULONG PathSize, FilePartSize, AnsiLength;
1133  PWCHAR LocalFilePart, Buffer;
1134  PWCHAR* FilePart;
1135 
1136  /* If the caller wants filepart, use a local wide buffer since this is A */
1137  FilePart = lpFilePart != NULL ? &LocalFilePart : NULL;
1138 
1139  /* Initialize stuff for Quickie */
1140  PathSize = 0;
1141  Buffer = NULL;
1142  ExtensionString.Buffer = PathString.Buffer = NULL;
1143 
1144  /* Get the UNICODE_STRING file name */
1146  if (!FileNameString) return 0;
1147 
1148  /* Did the caller specify an extension */
1149  if (lpExtension)
1150  {
1151  /* Yup, convert it into UNICODE_STRING */
1152  Status = Basep8BitStringToDynamicUnicodeString(&ExtensionString,
1153  lpExtension);
1154  if (!NT_SUCCESS(Status)) goto Quickie;
1155  }
1156 
1157  /* Did the caller specify a path */
1158  if (lpPath)
1159  {
1160  /* Yup, convert it into UNICODE_STRING */
1161  Status = Basep8BitStringToDynamicUnicodeString(&PathString, lpPath);
1162  if (!NT_SUCCESS(Status)) goto Quickie;
1163  }
1164 
1165  /* Allocate our output buffer */
1166  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nBufferLength * sizeof(WCHAR));
1167  if (!Buffer)
1168  {
1169  /* It failed, bail out */
1171  goto Quickie;
1172  }
1173 
1174  /* Now run the Wide search with the input buffer lengths */
1175  PathSize = SearchPathW(PathString.Buffer,
1176  FileNameString->Buffer,
1177  ExtensionString.Buffer,
1178  nBufferLength,
1179  Buffer,
1180  FilePart);
1181  if (PathSize <= nBufferLength)
1182  {
1183  /* It fits, but is it empty? If so, bail out */
1184  if (!PathSize) goto Quickie;
1185 
1186  /* The length above is inexact, we need it in ANSI */
1187  Status = RtlUnicodeToMultiByteSize(&AnsiLength, Buffer, PathSize * sizeof(WCHAR));
1188  if (!NT_SUCCESS(Status))
1189  {
1190  /* Conversion failed, fail the call */
1191  PathSize = 0;
1193  goto Quickie;
1194  }
1195 
1196  /* If the correct ANSI size is too big, return required length plus a NULL */
1197  if (AnsiLength >= nBufferLength)
1198  {
1199  PathSize = AnsiLength + 1;
1200  goto Quickie;
1201  }
1202 
1203  /* Now apply the final conversion to ANSI */
1205  nBufferLength - 1,
1206  &AnsiLength,
1207  Buffer,
1208  PathSize * sizeof(WCHAR));
1209  if (!NT_SUCCESS(Status))
1210  {
1211  /* Conversion failed, fail the whole call */
1212  PathSize = 0;
1214  goto Quickie;
1215  }
1216 
1217  /* NULL-terminate and return the real ANSI length */
1218  lpBuffer[AnsiLength] = ANSI_NULL;
1219  PathSize = AnsiLength;
1220 
1221  /* Now check if the user wanted file part size as well */
1222  if (lpFilePart)
1223  {
1224  /* If we didn't get a file part, clear the caller's */
1225  if (!LocalFilePart)
1226  {
1227  *lpFilePart = NULL;
1228  }
1229  else
1230  {
1231  /* Yep, so in this case get the length of the file part too */
1232  Status = RtlUnicodeToMultiByteSize(&FilePartSize,
1233  Buffer,
1234  (ULONG)(LocalFilePart - Buffer) *
1235  sizeof(WCHAR));
1236  if (!NT_SUCCESS(Status))
1237  {
1238  /* We failed to do that, so fail the whole call */
1240  PathSize = 0;
1241  }
1242 
1243  /* Return the file part buffer */
1244  *lpFilePart = lpBuffer + FilePartSize;
1245  }
1246  }
1247  }
1248  else
1249  {
1250  /* Our initial buffer guess was too small, allocate a bigger one */
1251  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1252  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize * sizeof(WCHAR));
1253  if (!Buffer)
1254  {
1255  /* Out of memory, fail everything */
1257  goto Quickie;
1258  }
1259 
1260  /* Do the search again -- it will fail, we just want the path size */
1261  PathSize = SearchPathW(PathString.Buffer,
1262  FileNameString->Buffer,
1263  ExtensionString.Buffer,
1264  PathSize,
1265  Buffer,
1266  FilePart);
1267  if (!PathSize) goto Quickie;
1268 
1269  /* Convert it to a correct size */
1270  Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize * sizeof(WCHAR));
1271  if (NT_SUCCESS(Status))
1272  {
1273  /* Make space for the NULL-char */
1274  PathSize++;
1275  }
1276  else
1277  {
1278  /* Conversion failed for some reason, fail the call */
1280  PathSize = 0;
1281  }
1282  }
1283 
1284 Quickie:
1285  /* Cleanup/complete path */
1286  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1287  if (ExtensionString.Buffer) RtlFreeUnicodeString(&ExtensionString);
1288  if (PathString.Buffer) RtlFreeUnicodeString(&PathString);
1289  return PathSize;
1290 }
1291 
1292 /*
1293  * @implemented
1294  */
1295 DWORD
1296 WINAPI
1303 {
1304  UNICODE_STRING FileNameString, ExtensionString, PathString, CallerBuffer;
1305  ULONG Flags;
1306  SIZE_T LengthNeeded, FilePartSize;
1307  NTSTATUS Status;
1308  DWORD Result = 0;
1309 
1310  /* Default flags for RtlDosSearchPath_Ustr */
1311  Flags = 6;
1312 
1313  /* Clear file part in case we fail */
1314  if (lpFilePart) *lpFilePart = NULL;
1315 
1316  /* Initialize path buffer for free later */
1317  PathString.Buffer = NULL;
1318 
1319  /* Convert filename to a unicode string and eliminate trailing spaces */
1320  RtlInitUnicodeString(&FileNameString, lpFileName);
1321  while ((FileNameString.Length >= sizeof(WCHAR)) &&
1322  (FileNameString.Buffer[(FileNameString.Length / sizeof(WCHAR)) - 1] == L' '))
1323  {
1324  FileNameString.Length -= sizeof(WCHAR);
1325  }
1326 
1327  /* Was it all just spaces? */
1328  if (!FileNameString.Length)
1329  {
1330  /* Fail out */
1332  goto Quickie;
1333  }
1334 
1335  /* Convert extension to a unicode string */
1336  RtlInitUnicodeString(&ExtensionString, lpExtension);
1337 
1338  /* Check if the user sent a path */
1339  if (lpPath)
1340  {
1341  /* Convert it to a unicode string too */
1342  Status = RtlInitUnicodeStringEx(&PathString, lpPath);
1343  if (NT_ERROR(Status))
1344  {
1345  /* Fail if it was too long */
1347  goto Quickie;
1348  }
1349  }
1350  else
1351  {
1352  /* A path wasn't sent, so compute it ourselves */
1353  PathString.Buffer = BaseComputeProcessSearchPath();
1354  if (!PathString.Buffer)
1355  {
1356  /* Fail if we couldn't compute it */
1358  goto Quickie;
1359  }
1360 
1361  /* See how big the computed path is */
1362  LengthNeeded = lstrlenW(PathString.Buffer);
1364  {
1365  /* Fail if it's too long */
1367  goto Quickie;
1368  }
1369 
1370  /* Set the path size now that we have it */
1371  PathString.MaximumLength = PathString.Length = (USHORT)LengthNeeded * sizeof(WCHAR);
1372 
1373  /* Request SxS isolation from RtlDosSearchPath_Ustr */
1374  Flags |= 1;
1375  }
1376 
1377  /* Create the string that describes the output buffer from the caller */
1378  CallerBuffer.Length = 0;
1379  CallerBuffer.Buffer = lpBuffer;
1380 
1381  /* How much space does the caller have? */
1383  {
1384  /* Add it into the string */
1385  CallerBuffer.MaximumLength = (USHORT)nBufferLength * sizeof(WCHAR);
1386  }
1387  else
1388  {
1389  /* Caller wants too much, limit it to the maximum length of a string */
1390  CallerBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES;
1391  }
1392 
1393  /* Call Rtl to do the work */
1395  &PathString,
1396  &FileNameString,
1397  &ExtensionString,
1398  &CallerBuffer,
1399  NULL,
1400  NULL,
1401  &FilePartSize,
1402  &LengthNeeded);
1403  if (NT_ERROR(Status))
1404  {
1405  /* Check for unusual status codes */
1407  {
1408  /* Print them out since maybe an app needs fixing */
1409  DbgPrint("%s on file %wZ failed; NTSTATUS = %08lx\n",
1410  __FUNCTION__,
1411  &FileNameString,
1412  Status);
1413  DbgPrint(" Path = %wZ\n", &PathString);
1414  }
1415 
1416  /* Check if the failure was due to a small buffer */
1418  {
1419  /* Check if the length was actually too big for Rtl to work with */
1420  Result = LengthNeeded / sizeof(WCHAR);
1421  if (Result > 0xFFFFFFFF) BaseSetLastNTError(STATUS_NAME_TOO_LONG);
1422  }
1423  else
1424  {
1425  /* Some other error, set the error code */
1427  }
1428  }
1429  else
1430  {
1431  /* It worked! Write the file part now */
1432  if (lpFilePart) *lpFilePart = &lpBuffer[FilePartSize];
1433 
1434  /* Convert the final result length */
1435  Result = CallerBuffer.Length / sizeof(WCHAR);
1436  }
1437 
1438 Quickie:
1439  /* Check if there was a dynamic path string to free */
1440  if ((PathString.Buffer != lpPath) && (PathString.Buffer))
1441  {
1442  /* And free it */
1443  RtlFreeHeap(RtlGetProcessHeap(), 0, PathString.Buffer);
1444  }
1445 
1446  /* Return the final result length */
1447  return Result;
1448 }
1449 
1450 /*
1451  * @implemented
1452  */
1453 DWORD
1454 WINAPI
1456  OUT LPWSTR lpszLongPath,
1457  IN DWORD cchBuffer)
1458 {
1459  PWCHAR Path, Original, First, Last, Buffer, Src, Dst;
1461  WCHAR LastChar;
1462  HANDLE FindHandle;
1463  ULONG ErrorMode;
1464  BOOLEAN Found = FALSE;
1465  WIN32_FIND_DATAW FindFileData;
1466 
1467  /* Initialize so Quickie knows there's nothing to do */
1468  Buffer = Original = NULL;
1469  ReturnLength = 0;
1470 
1471  /* First check if the input path was obviously NULL */
1472  if (!lpszShortPath)
1473  {
1474  /* Fail the request */
1476  return 0;
1477  }
1478 
1479  /* We will be touching removed, removable drives -- don't warn the user */
1481 
1482  /* Do a simple check to see if the path exists */
1483  if (GetFileAttributesW(lpszShortPath) == INVALID_FILE_ATTRIBUTES)
1484  {
1485  /* It doesn't, so fail */
1486  ReturnLength = 0;
1487  goto Quickie;
1488  }
1489 
1490  /* Now get a pointer to the actual path, skipping indicators */
1491  Path = SkipPathTypeIndicator_U((LPWSTR)lpszShortPath);
1492 
1493  /* Is there any path or filename in there? */
1494  if (!(Path) ||
1495  (*Path == UNICODE_NULL) ||
1496  !(FindLFNorSFN_U(Path, &First, &Last, FALSE)))
1497  {
1498  /* There isn't, so the long path is simply the short path */
1499  ReturnLength = wcslen(lpszShortPath);
1500 
1501  /* Is there space for it? */
1502  if ((cchBuffer > ReturnLength) && (lpszLongPath))
1503  {
1504  /* Make sure the pointers aren't already the same */
1505  if (lpszLongPath != lpszShortPath)
1506  {
1507  /* They're not -- copy the short path into the long path */
1508  RtlMoveMemory(lpszLongPath,
1509  lpszShortPath,
1510  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1511  }
1512  }
1513  else
1514  {
1515  /* Otherwise, let caller know we need a bigger buffer, include NULL */
1516  ReturnLength++;
1517  }
1518  goto Quickie;
1519  }
1520 
1521  /* We are still in the game -- compute the current size */
1522  Length = wcslen(lpszShortPath) + sizeof(ANSI_NULL);
1523  Original = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
1524  if (!Original) goto ErrorQuickie;
1525 
1526  /* Make a copy of it */
1527  RtlMoveMemory(Original, lpszShortPath, Length * sizeof(WCHAR));
1528 
1529  /* Compute the new first and last markers */
1530  First = &Original[First - lpszShortPath];
1531  Last = &Original[Last - lpszShortPath];
1532 
1533  /* Set the current destination pointer for a copy */
1534  Dst = lpszLongPath;
1535 
1536  /*
1537  * Windows allows the paths to overlap -- we have to be careful with this and
1538  * see if it's same to do so, and if not, allocate our own internal buffer
1539  * that we'll return at the end.
1540  *
1541  * This is also why we use RtlMoveMemory everywhere. Don't use RtlCopyMemory!
1542  */
1543  if ((cchBuffer) && (lpszLongPath) &&
1544  (((lpszLongPath >= lpszShortPath) && (lpszLongPath < &lpszShortPath[Length])) ||
1545  ((lpszLongPath < lpszShortPath) && (&lpszLongPath[cchBuffer] >= lpszShortPath))))
1546  {
1547  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchBuffer * sizeof(WCHAR));
1548  if (!Buffer) goto ErrorQuickie;
1549 
1550  /* New destination */
1551  Dst = Buffer;
1552  }
1553 
1554  /* Prepare for the loop */
1555  Src = Original;
1556  ReturnLength = 0;
1557  while (TRUE)
1558  {
1559  /* Current delta in the loop */
1560  Length = First - Src;
1561 
1562  /* Update the return length by it */
1563  ReturnLength += Length;
1564 
1565  /* Is there a delta? If so, is there space and buffer for it? */
1566  if ((Length) && (cchBuffer > ReturnLength) && (lpszLongPath))
1567  {
1568  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR));
1569  Dst += Length;
1570  }
1571 
1572  /* "Terminate" this portion of the path's substring so we can do a find */
1573  LastChar = *Last;
1574  *Last = UNICODE_NULL;
1575  FindHandle = FindFirstFileW(Original, &FindFileData);
1576  *Last = LastChar;
1577 
1578  /* This portion wasn't found, so fail */
1579  if (FindHandle == INVALID_HANDLE_VALUE)
1580  {
1581  ReturnLength = 0;
1582  break;
1583  }
1584 
1585  /* Close the find handle */
1586  FindClose(FindHandle);
1587 
1588  /* Now check the length of the long name */
1589  Length = wcslen(FindFileData.cFileName);
1590  if (Length)
1591  {
1592  /* This is our new first marker */
1593  First = FindFileData.cFileName;
1594  }
1595  else
1596  {
1597  /* Otherwise, the name is the delta between our current markers */
1598  Length = Last - First;
1599  }
1600 
1601  /* Update the return length with the short name length, if any */
1602  ReturnLength += Length;
1603 
1604  /* Once again check for appropriate space and buffer */
1605  if ((cchBuffer > ReturnLength) && (lpszLongPath))
1606  {
1607  /* And do the copy if there is */
1608  RtlMoveMemory(Dst, First, Length * sizeof(WCHAR));
1609  Dst += Length;
1610  }
1611 
1612  /* Now update the source pointer */
1613  Src = Last;
1614  if (*Src == UNICODE_NULL) break;
1615 
1616  /* Are there more names in there? */
1617  Found = FindLFNorSFN_U(Src, &First, &Last, FALSE);
1618  if (!Found) break;
1619  }
1620 
1621  /* The loop is done, is there anything left? */
1622  if (ReturnLength)
1623  {
1624  /* Get the length of the straggling path */
1625  Length = wcslen(Src);
1626  ReturnLength += Length;
1627 
1628  /* Once again check for appropriate space and buffer */
1629  if ((cchBuffer > ReturnLength) && (lpszLongPath))
1630  {
1631  /* And do the copy if there is -- accounting for NULL here */
1632  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1633 
1634  /* What about our buffer? */
1635  if (Buffer)
1636  {
1637  /* Copy it into the caller's long path */
1638  RtlMoveMemory(lpszLongPath,
1639  Buffer,
1640  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1641  }
1642  }
1643  else
1644  {
1645  /* Buffer is too small, let the caller know, making space for NULL */
1646  ReturnLength++;
1647  }
1648  }
1649 
1650  /* We're all done */
1651  goto Quickie;
1652 
1653 ErrorQuickie:
1654  /* This is the goto for memory failures */
1656 
1657 Quickie:
1658  /* General function end: free memory, restore error mode, return length */
1659  if (Original) RtlFreeHeap(RtlGetProcessHeap(), 0, Original);
1660  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1661  SetErrorMode(ErrorMode);
1662  return ReturnLength;
1663 }
1664 
1665 /*
1666  * @implemented
1667  */
1668 DWORD
1669 WINAPI
1671  OUT LPSTR lpszLongPath,
1672  IN DWORD cchBuffer)
1673 {
1675  PWCHAR LongPath;
1676  NTSTATUS Status;
1677  UNICODE_STRING LongPathUni, ShortPathUni;
1678  ANSI_STRING LongPathAnsi;
1679  WCHAR LongPathBuffer[MAX_PATH];
1680 
1681  LongPath = NULL;
1682  LongPathAnsi.Buffer = NULL;
1683  ShortPathUni.Buffer = NULL;
1684  Result = 0;
1685 
1686  if (!lpszShortPath)
1687  {
1689  return 0;
1690  }
1691 
1692  Status = Basep8BitStringToDynamicUnicodeString(&ShortPathUni, lpszShortPath);
1693  if (!NT_SUCCESS(Status)) goto Quickie;
1694 
1695  LongPath = LongPathBuffer;
1696 
1697  PathLength = GetLongPathNameW(ShortPathUni.Buffer, LongPathBuffer, MAX_PATH);
1698  if (PathLength >= MAX_PATH)
1699  {
1700  LongPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLength * sizeof(WCHAR));
1701  if (!LongPath)
1702  {
1703  PathLength = 0;
1705  }
1706  else
1707  {
1708  PathLength = GetLongPathNameW(ShortPathUni.Buffer, LongPath, PathLength);
1709  }
1710  }
1711 
1712  if (!PathLength) goto Quickie;
1713 
1714  ShortPathUni.MaximumLength = (USHORT)PathLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
1715  LongPathUni.Buffer = LongPath;
1716  LongPathUni.Length = (USHORT)PathLength * sizeof(WCHAR);
1717 
1718  Status = BasepUnicodeStringTo8BitString(&LongPathAnsi, &LongPathUni, TRUE);
1719  if (!NT_SUCCESS(Status))
1720  {
1722  Result = 0;
1723  }
1724 
1725  Result = LongPathAnsi.Length;
1726  if ((lpszLongPath) && (cchBuffer > LongPathAnsi.Length))
1727  {
1728  RtlMoveMemory(lpszLongPath, LongPathAnsi.Buffer, LongPathAnsi.Length);
1729  lpszLongPath[Result] = ANSI_NULL;
1730  }
1731  else
1732  {
1733  Result = LongPathAnsi.Length + sizeof(ANSI_NULL);
1734  }
1735 
1736 Quickie:
1737  if (ShortPathUni.Buffer) RtlFreeUnicodeString(&ShortPathUni);
1738  if (LongPathAnsi.Buffer) RtlFreeAnsiString(&LongPathAnsi);
1739  if ((LongPath) && (LongPath != LongPathBuffer))
1740  {
1741  RtlFreeHeap(RtlGetProcessHeap(), 0, LongPath);
1742  }
1743  return Result;
1744 }
1745 
1746 /*
1747  * @implemented
1748  */
1749 DWORD
1750 WINAPI
1752  OUT LPSTR lpszShortPath,
1753  IN DWORD cchBuffer)
1754 {
1756  PWCHAR ShortPath;
1757  NTSTATUS Status;
1758  UNICODE_STRING LongPathUni, ShortPathUni;
1759  ANSI_STRING ShortPathAnsi;
1760  WCHAR ShortPathBuffer[MAX_PATH];
1761 
1762  ShortPath = NULL;
1763  ShortPathAnsi.Buffer = NULL;
1764  LongPathUni.Buffer = NULL;
1765  Result = 0;
1766 
1767  if (!lpszLongPath)
1768  {
1770  return 0;
1771  }
1772 
1773  Status = Basep8BitStringToDynamicUnicodeString(&LongPathUni, lpszLongPath);
1774  if (!NT_SUCCESS(Status)) goto Quickie;
1775 
1776  ShortPath = ShortPathBuffer;
1777 
1778  PathLength = GetShortPathNameW(LongPathUni.Buffer, ShortPathBuffer, MAX_PATH);
1779  if (PathLength >= MAX_PATH)
1780  {
1781  ShortPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLength * sizeof(WCHAR));
1782  if (!ShortPath)
1783  {
1784  PathLength = 0;
1786  }
1787  else
1788  {
1789  PathLength = GetShortPathNameW(LongPathUni.Buffer, ShortPath, PathLength);
1790  }
1791  }
1792 
1793  if (!PathLength) goto Quickie;
1794 
1795  LongPathUni.MaximumLength = (USHORT)PathLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
1796  ShortPathUni.Buffer = ShortPath;
1797  ShortPathUni.Length = (USHORT)PathLength * sizeof(WCHAR);
1798 
1799  Status = BasepUnicodeStringTo8BitString(&ShortPathAnsi, &ShortPathUni, TRUE);
1800  if (!NT_SUCCESS(Status))
1801  {
1803  Result = 0;
1804  }
1805 
1806  Result = ShortPathAnsi.Length;
1807  if ((lpszShortPath) && (cchBuffer > ShortPathAnsi.Length))
1808  {
1809  RtlMoveMemory(lpszShortPath, ShortPathAnsi.Buffer, ShortPathAnsi.Length);
1810  lpszShortPath[Result] = ANSI_NULL;
1811  }
1812  else
1813  {
1814  Result = ShortPathAnsi.Length + sizeof(ANSI_NULL);
1815  }
1816 
1817 Quickie:
1818  if (LongPathUni.Buffer) RtlFreeUnicodeString(&LongPathUni);
1819  if (ShortPathAnsi.Buffer) RtlFreeAnsiString(&ShortPathAnsi);
1820  if ((ShortPath) && (ShortPath != ShortPathBuffer))
1821  {
1822  RtlFreeHeap(RtlGetProcessHeap(), 0, ShortPath);
1823  }
1824  return Result;
1825 }
1826 
1827 /*
1828  * @implemented
1829  */
1830 DWORD
1831 WINAPI
1833  OUT LPWSTR lpszShortPath,
1834  IN DWORD cchBuffer)
1835 {
1836  PWCHAR Path, Original, First, Last, Buffer, Src, Dst;
1838  WCHAR LastChar;
1839  HANDLE FindHandle;
1840  ULONG ErrorMode;
1841  BOOLEAN Found = FALSE;
1842  WIN32_FIND_DATAW FindFileData;
1843 
1844  /* Initialize so Quickie knows there's nothing to do */
1845  Buffer = Original = NULL;
1846  ReturnLength = 0;
1847 
1848  /* First check if the input path was obviously NULL */
1849  if (!lpszLongPath)
1850  {
1851  /* Fail the request */
1853  return 0;
1854  }
1855 
1856  /* We will be touching removed, removable drives -- don't warn the user */
1858 
1859  /* Do a simple check to see if the path exists */
1860  if (GetFileAttributesW(lpszLongPath) == INVALID_FILE_ATTRIBUTES)
1861  {
1862  /* Windows checks for an application compatibility flag to allow this */
1863  if (!(NtCurrentPeb()) || !(NtCurrentPeb()->AppCompatFlags.LowPart & GetShortPathNameNT4))
1864  {
1865  /* It doesn't, so fail */
1866  ReturnLength = 0;
1867  goto Quickie;
1868  }
1869  }
1870 
1871  /* Now get a pointer to the actual path, skipping indicators */
1872  Path = SkipPathTypeIndicator_U((LPWSTR)lpszLongPath);
1873 
1874  /* Is there any path or filename in there? */
1875  if (!(Path) ||
1876  (*Path == UNICODE_NULL) ||
1877  !(FindLFNorSFN_U(Path, &First, &Last, TRUE)))
1878  {
1879  /* There isn't, so the long path is simply the short path */
1880  ReturnLength = wcslen(lpszLongPath);
1881 
1882  /* Is there space for it? */
1883  if ((cchBuffer > ReturnLength) && (lpszShortPath))
1884  {
1885  /* Make sure the pointers aren't already the same */
1886  if (lpszLongPath != lpszShortPath)
1887  {
1888  /* They're not -- copy the short path into the long path */
1889  RtlMoveMemory(lpszShortPath,
1890  lpszLongPath,
1891  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1892  }
1893  }
1894  else
1895  {
1896  /* Otherwise, let caller know we need a bigger buffer, include NULL */
1897  ReturnLength++;
1898  }
1899  goto Quickie;
1900  }
1901 
1902  /* We are still in the game -- compute the current size */
1903  Length = wcslen(lpszLongPath) + sizeof(ANSI_NULL);
1904  Original = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
1905  if (!Original) goto ErrorQuickie;
1906 
1907  /* Make a copy of it */
1908  wcsncpy(Original, lpszLongPath, Length);
1909 
1910  /* Compute the new first and last markers */
1911  First = &Original[First - lpszLongPath];
1912  Last = &Original[Last - lpszLongPath];
1913 
1914  /* Set the current destination pointer for a copy */
1915  Dst = lpszShortPath;
1916 
1917  /*
1918  * Windows allows the paths to overlap -- we have to be careful with this and
1919  * see if it's same to do so, and if not, allocate our own internal buffer
1920  * that we'll return at the end.
1921  *
1922  * This is also why we use RtlMoveMemory everywhere. Don't use RtlCopyMemory!
1923  */
1924  if ((cchBuffer) && (lpszShortPath) &&
1925  (((lpszShortPath >= lpszLongPath) && (lpszShortPath < &lpszLongPath[Length])) ||
1926  ((lpszShortPath < lpszLongPath) && (&lpszShortPath[cchBuffer] >= lpszLongPath))))
1927  {
1928  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchBuffer * sizeof(WCHAR));
1929  if (!Buffer) goto ErrorQuickie;
1930 
1931  /* New destination */
1932  Dst = Buffer;
1933  }
1934 
1935  /* Prepare for the loop */
1936  Src = Original;
1937  ReturnLength = 0;
1938  while (TRUE)
1939  {
1940  /* Current delta in the loop */
1941  Length = First - Src;
1942 
1943  /* Update the return length by it */
1944  ReturnLength += Length;
1945 
1946  /* Is there a delta? If so, is there space and buffer for it? */
1947  if ((Length) && (cchBuffer > ReturnLength) && (lpszShortPath))
1948  {
1949  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR));
1950  Dst += Length;
1951  }
1952 
1953  /* "Terminate" this portion of the path's substring so we can do a find */
1954  LastChar = *Last;
1955  *Last = UNICODE_NULL;
1956  FindHandle = FindFirstFileW(Original, &FindFileData);
1957  *Last = LastChar;
1958 
1959  /* This portion wasn't found, so fail */
1960  if (FindHandle == INVALID_HANDLE_VALUE)
1961  {
1962  ReturnLength = 0;
1963  break;
1964  }
1965 
1966  /* Close the find handle */
1967  FindClose(FindHandle);
1968 
1969  /* Now check the length of the short name */
1970  Length = wcslen(FindFileData.cAlternateFileName);
1971  if (Length)
1972  {
1973  /* This is our new first marker */
1974  First = FindFileData.cAlternateFileName;
1975  }
1976  else
1977  {
1978  /* Otherwise, the name is the delta between our current markers */
1979  Length = Last - First;
1980  }
1981 
1982  /* Update the return length with the short name length, if any */
1983  ReturnLength += Length;
1984 
1985  /* Once again check for appropriate space and buffer */
1986  if ((cchBuffer > ReturnLength) && (lpszShortPath))
1987  {
1988  /* And do the copy if there is */
1989  RtlMoveMemory(Dst, First, Length * sizeof(WCHAR));
1990  Dst += Length;
1991  }
1992 
1993  /* Now update the source pointer */
1994  Src = Last;
1995  if (*Src == UNICODE_NULL) break;
1996 
1997  /* Are there more names in there? */
1998  Found = FindLFNorSFN_U(Src, &First, &Last, TRUE);
1999  if (!Found) break;
2000  }
2001 
2002  /* The loop is done, is there anything left? */
2003  if (ReturnLength)
2004  {
2005  /* Get the length of the straggling path */
2006  Length = wcslen(Src);
2007  ReturnLength += Length;
2008 
2009  /* Once again check for appropriate space and buffer */
2010  if ((cchBuffer > ReturnLength) && (lpszShortPath))
2011  {
2012  /* And do the copy if there is -- accounting for NULL here */
2013  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR) + sizeof(UNICODE_NULL));
2014 
2015  /* What about our buffer? */
2016  if (Buffer)
2017  {
2018  /* Copy it into the caller's long path */
2019  RtlMoveMemory(lpszShortPath,
2020  Buffer,
2021  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
2022  }
2023  }
2024  else
2025  {
2026  /* Buffer is too small, let the caller know, making space for NULL */
2027  ReturnLength++;
2028  }
2029  }
2030 
2031  /* We're all done */
2032  goto Quickie;
2033 
2034 ErrorQuickie:
2035  /* This is the goto for memory failures */
2037 
2038 Quickie:
2039  /* General function end: free memory, restore error mode, return length */
2040  if (Original) RtlFreeHeap(RtlGetProcessHeap(), 0, Original);
2041  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
2042  SetErrorMode(ErrorMode);
2043  return ReturnLength;
2044 }
2045 
2046 /*
2047  * @implemented
2048  *
2049  * NOTE: Windows returns a dos/short (8.3) path
2050  */
2051 DWORD
2052 WINAPI
2054  OUT LPSTR lpBuffer)
2055 {
2056  WCHAR BufferW[MAX_PATH];
2057  DWORD ret;
2058 
2059  ret = GetTempPathW(MAX_PATH, BufferW);
2060 
2061  if (!ret) return 0;
2062 
2063  if (ret > MAX_PATH)
2064  {
2066  return 0;
2067  }
2068 
2069  return FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1);
2070 }
2071 
2072 /*
2073  * @implemented
2074  *
2075  * ripped from wine
2076  */
2077 DWORD
2078 WINAPI
2080  OUT LPWSTR path)
2081 {
2082  static const WCHAR tmp[] = { 'T', 'M', 'P', 0 };
2083  static const WCHAR temp[] = { 'T', 'E', 'M', 'P', 0 };
2084  static const WCHAR userprofile[] = { 'U','S','E','R','P','R','O','F','I','L','E',0 };
2085  WCHAR tmp_path[MAX_PATH];
2086  WCHAR full_tmp_path[MAX_PATH];
2087  UINT ret;
2088 
2089  DPRINT("%u,%p\n", count, path);
2090 
2091  if (!(ret = GetEnvironmentVariableW( tmp, tmp_path, MAX_PATH )) &&
2092  !(ret = GetEnvironmentVariableW( temp, tmp_path, MAX_PATH )) &&
2093  !(ret = GetEnvironmentVariableW( userprofile, tmp_path, MAX_PATH )) &&
2094  !(ret = GetWindowsDirectoryW( tmp_path, MAX_PATH )))
2095  {
2096  return 0;
2097  }
2098 
2099  if (ret > MAX_PATH)
2100  {
2102  return 0;
2103  }
2104 
2105  ret = GetFullPathNameW(tmp_path, MAX_PATH, full_tmp_path, NULL);
2106  if (!ret) return 0;
2107 
2108  if (ret > MAX_PATH - 2)
2109  {
2111  return 0;
2112  }
2113 
2114  if (full_tmp_path[ret-1] != '\\')
2115  {
2116  full_tmp_path[ret++] = '\\';
2117  full_tmp_path[ret] = '\0';
2118  }
2119 
2120  ret++; /* add space for terminating 0 */
2121 
2122  if (count >= ret)
2123  {
2124  lstrcpynW(path, full_tmp_path, count);
2125  /* the remaining buffer must be zeroed up to 32766 bytes in XP or 32767
2126  * bytes after it, we will assume the > XP behavior for now */
2127  memset(path + ret, 0, (min(count, 32767) - ret) * sizeof(WCHAR));
2128  ret--; /* return length without 0 */
2129  }
2130  else if (count)
2131  {
2132  /* the buffer must be cleared if contents will not fit */
2133  memset(path, 0, count * sizeof(WCHAR));
2134  }
2135 
2136  DPRINT("GetTempPathW returning %u, %S\n", ret, path);
2137  return ret;
2138 }
2139 
2140 /*
2141  * @implemented
2142  */
2143 DWORD
2144 WINAPI
2146  OUT LPSTR lpBuffer)
2147 {
2149  NTSTATUS Status;
2151  ULONG MaxLength;
2152 
2153  StaticString = &NtCurrentTeb()->StaticUnicodeString;
2154 
2155  MaxLength = nBufferLength;
2157  {
2158  MaxLength = UNICODE_STRING_MAX_BYTES - 1;
2159  }
2160 
2162  StaticString->Buffer);
2165  StaticString->Length);
2166  if (!NT_SUCCESS(Status))
2167  {
2169  return 0;
2170  }
2171 
2172  if (MaxLength <= nBufferLength)
2173  {
2174  return nBufferLength + 1;
2175  }
2176 
2177  AnsiString.Buffer = lpBuffer;
2178  AnsiString.MaximumLength = (USHORT)MaxLength;
2180  if (!NT_SUCCESS(Status))
2181  {
2183  return 0;
2184  }
2185 
2186  return AnsiString.Length;
2187 }
2188 
2189 /*
2190  * @implemented
2191  */
2192 DWORD
2193 WINAPI
2196 {
2197  return RtlGetCurrentDirectory_U(nBufferLength * sizeof(WCHAR), lpBuffer) / sizeof(WCHAR);
2198 }
2199 
2200 /*
2201  * @implemented
2202  */
2203 BOOL
2204 WINAPI
2206 {
2208  NTSTATUS Status;
2209 
2210  if (!lpPathName)
2211  {
2213  return FALSE;
2214  }
2215 
2217  if (!DirName) return FALSE;
2218 
2219  if (CheckForSameCurdir(DirName)) return TRUE;
2220 
2222  if (NT_SUCCESS(Status)) return TRUE;
2223 
2224  if ((*DirName->Buffer != L'"') || (DirName->Length <= 2))
2225  {
2227  return 0;
2228  }
2229 
2231  if (!DirName) return FALSE;
2232 
2234  if (!NT_SUCCESS(Status))
2235  {
2237  return FALSE;
2238  }
2239 
2240  return TRUE;
2241 }
2242 
2243 /*
2244  * @implemented
2245  */
2246 BOOL
2247 WINAPI
2249 {
2250  NTSTATUS Status;
2252 
2253  if (!lpPathName)
2254  {
2256  return FALSE;
2257  }
2258 
2260  if (NT_SUCCESS(Status))
2261  {
2263  {
2265  }
2266  }
2267 
2268  if (!NT_SUCCESS(Status))
2269  {
2271  return FALSE;
2272  }
2273 
2274  return TRUE;
2275 }
2276 
2277 /*
2278  * @implemented
2279  */
2280 UINT
2281 WINAPI
2283  IN UINT uSize)
2284 {
2286  NTSTATUS Status;
2287  ULONG AnsiLength;
2288 
2289  /* Get the correct size of the Unicode Base directory */
2290  Status = RtlUnicodeToMultiByteSize(&AnsiLength,
2293  if (!NT_SUCCESS(Status)) return 0;
2294 
2295  if (uSize < AnsiLength) return AnsiLength;
2296 
2297  RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize);
2298 
2301  FALSE);
2302  if (!NT_SUCCESS(Status)) return 0;
2303 
2304  return AnsiString.Length;
2305 }
2306 
2307 /*
2308  * @implemented
2309  */
2310 UINT
2311 WINAPI
2313  IN UINT uSize)
2314 {
2316 
2318  if ((uSize * sizeof(WCHAR)) >= ReturnLength)
2319  {
2324 
2326  }
2327 
2328  return ReturnLength / sizeof(WCHAR);
2329 }
2330 
2331 /*
2332  * @implemented
2333  */
2334 UINT
2335 WINAPI
2337  IN UINT uSize)
2338 {
2339  /* Is this a TS installation? */
2341 
2342  /* Otherwise, call the System API */
2343  return GetSystemWindowsDirectoryA(lpBuffer, uSize);
2344 }
2345 
2346 /*
2347  * @implemented
2348  */
2349 UINT
2350 WINAPI
2352  IN UINT uSize)
2353 {
2354  /* Is this a TS installation? */
2356 
2357  /* Otherwise, call the System API */
2358  return GetSystemWindowsDirectoryW(lpBuffer, uSize);
2359 }
2360 
2361 /*
2362  * @implemented
2363  */
2364 UINT
2365 WINAPI
2367  IN UINT uSize)
2368 {
2370  NTSTATUS Status;
2371  ULONG AnsiLength;
2372 
2373  /* Get the correct size of the Unicode Base directory */
2374  Status = RtlUnicodeToMultiByteSize(&AnsiLength,
2377  if (!NT_SUCCESS(Status)) return 0;
2378 
2379  if (uSize < AnsiLength) return AnsiLength;
2380 
2381  RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize);
2382 
2385  FALSE);
2386  if (!NT_SUCCESS(Status)) return 0;
2387 
2388  return AnsiString.Length;
2389 }
2390 
2391 /*
2392  * @implemented
2393  */
2394 UINT
2395 WINAPI
2397  IN UINT uSize)
2398 {
2400 
2402  if ((uSize * sizeof(WCHAR)) >= ReturnLength)
2403  {
2408 
2410  }
2411 
2412  return ReturnLength / sizeof(WCHAR);
2413 }
2414 
2415 /*
2416  * @unimplemented
2417  */
2418 UINT
2419 WINAPI
2421  IN UINT uSize)
2422 {
2423 #ifdef _WIN64
2424  UNIMPLEMENTED;
2425  return 0;
2426 #else
2428  return 0;
2429 #endif
2430 }
2431 
2432 /*
2433  * @unimplemented
2434  */
2435 UINT
2436 WINAPI
2438  IN UINT uSize)
2439 {
2440 #ifdef _WIN64
2441  UNIMPLEMENTED;
2442  return 0;
2443 #else
2445  return 0;
2446 #endif
2447 }
2448 
2449 /* EOF */
IN CINT OUT PVOID IN ULONG OUT PULONG ResultLength
Definition: conport.c:47
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
UINT WINAPI SetErrorMode(IN UINT uMode)
Definition: except.c:753
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4693
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
UNICODE_STRING BaseDefaultPath
Definition: path.c:21
PVOID PVOID PWCHAR PVOID Environment
Definition: env.c:45
#define IN
Definition: typedefs.h:38
BOOL WINAPI BasepIsCurDirAllowedForPlainExeNames(VOID)
Definition: path.c:780
PUNICODE_STRING WINAPI Basep8BitStringToStaticUnicodeString(IN LPCSTR String)
Definition: utils.c:188
UINT WINAPI GetSystemWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2396
_In_ LPCSTR _In_opt_ LPCSTR _In_ DWORD _Out_opt_ LPSTR * lpFilePart
Definition: winbase.h:3015
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
UINT WINAPI GetSystemWindowsDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2366
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
*BytesInUnicodeString PWCH UnicodeString
Definition: rtlfuncs.h:1980
BOOL WINAPI IsShortName_U(IN PWCHAR Name, IN ULONG Length)
Definition: path.c:560
#define SEM_FAILCRITICALERRORS
Definition: rtltypes.h:69
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4693
#define DbgPrint
Definition: loader.c:25
USHORT MaximumLength
Definition: env_spec_w32.h:370
PRTL_CONVERT_STRINGA BasepUnicodeStringTo8BitString
Definition: utils.c:27
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
__wchar_t WCHAR
Definition: xmlstorage.h:180
NTSYSAPI NTSTATUS WINAPI RtlInitAnsiStringEx(PANSI_STRING, PCSZ)
GLuint GLuint GLsizei count
Definition: gl.h:1545
char CHAR
Definition: xmlstorage.h:175
NTSYSAPI NTSTATUS NTAPI RtlUnicodeToMultiByteSize(PULONG MbSize, PCWCH UnicodeString, ULONG UnicodeSize)
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
IN PDCB IN POEM_STRING IN PUNICODE_STRING UnicodeName
Definition: fatprocs.h:1294
static CHAR AppName[MAX_PATH]
Definition: dem.c:252
UINT WINAPI GetSystemDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2282
PVOID gpTermsrvGetWindowsDirectoryA
Definition: path.c:23
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
NTSYSAPI NTSTATUS NTAPI RtlEnterCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
#define InterlockedCompareExchange
Definition: interlocked.h:104
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
VOID NTAPI RtlReleasePebLock(VOID)
Definition: libsupp.c:82
uint16_t * PWCHAR
Definition: typedefs.h:54
char * LPSTR
Definition: xmlstorage.h:182
#define WCHAR
Definition: msvc.h:43
static USHORT PathLength
#define UNICODE_STRING_MAX_BYTES
#define lstrlenW
Definition: compat.h:407
BOOL WINAPI NeedCurrentDirectoryForExePathA(IN LPCSTR ExeName)
Definition: path.c:968
UNICODE_STRING BaseDllDirectory
Definition: path.c:21
DWORD ret
Definition: path.c:47
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define lstrcpynW
Definition: compat.h:397
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:64
UINT WINAPI GetWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2351
LPWSTR WINAPI BaseComputeProcessSearchPath(VOID)
Definition: path.c:395
DWORD WINAPI GetLongPathNameA(IN LPCSTR lpszShortPath, OUT LPSTR lpszLongPath, IN DWORD cchBuffer)
Definition: path.c:1670
DWORD WINAPI GetFullPathNameA(IN LPCSTR lpFileName, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart)
Definition: path.c:992
WCHAR First[]
Definition: FormatMessage.c:11
ULONG NTAPI RtlGetFullPathName_U(_In_ PCWSTR FileName, _In_ ULONG Size, _Out_z_bytecap_(Size) PWSTR Buffer, _Out_opt_ PWSTR *ShortName)
Definition: path.c:1868
DWORD WINAPI GetDllDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:914
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
BOOL WINAPI IsLongName_U(IN PWCHAR FileName, IN ULONG Length)
Definition: path.c:647
BOOL WINAPI FindLFNorSFN_U(IN PWCHAR Path, OUT PWCHAR *First, OUT PWCHAR *Last, IN BOOL UseShort)
Definition: path.c:681
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
BOOLEAN WINAPI Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString, IN LPCSTR String)
Definition: utils.c:225
BASE_SEARCH_PATH_TYPE BaseProcessOrderNoCurrent[BaseSearchPathMax]
Definition: path.c:54
DWORD WINAPI GetTempPathW(IN DWORD count, OUT LPWSTR path)
Definition: path.c:2079
#define UNICODE_NULL
#define ANSI_NULL
DWORD WINAPI SearchPathA(IN LPCSTR lpPath OPTIONAL, IN LPCSTR lpFileName, IN LPCSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart OPTIONAL)
Definition: path.c:1122
NTSYSAPI NTSTATUS NTAPI RtlLeaveCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
PWCHAR WINAPI BasepEndOfDirName(IN PWCHAR FileName)
Definition: path.c:89
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:802
PWCHAR WINAPI SkipPathTypeIndicator_U(IN LPWSTR Path)
Definition: path.c:739
static DWORD cchBuffer
Definition: fusion.c:83
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:163
unsigned char BOOLEAN
NTSYSAPI NTSTATUS NTAPI RtlQueryEnvironmentVariable_U(_In_opt_ PWSTR Environment, _In_ PCUNICODE_STRING Name, _Out_ PUNICODE_STRING Value)
smooth NULL
Definition: ftsmooth.c:416
_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
BOOL WINAPI IsDBCSLeadByte(BYTE TestByte)
Definition: nls.c:2130
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
UINT WINAPI GetSystemWow64DirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2437
DWORD BaseSetLastNTError(IN NTSTATUS Status)
Definition: reactos.cpp:166
BOOL WINAPI NeedCurrentDirectoryForExePathW(IN LPCWSTR ExeName)
Definition: path.c:956
BOOL WINAPI SetDllDirectoryA(IN LPCSTR lpPathName)
Definition: path.c:837
return Found
Definition: dirsup.c:1270
const char * LPCSTR
Definition: xmlstorage.h:183
BOOLEAN WINAPI CheckForSameCurdir(IN PUNICODE_STRING DirName)
Definition: path.c:518
PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry
Definition: proc.c:25
_In_ LPCSTR _In_opt_ LPCSTR _In_ DWORD nBufferLength
Definition: winbase.h:3011
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:484
PVOID gpTermsrvGetWindowsDirectoryW
Definition: path.c:24
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:585
NTSYSAPI NTSTATUS NTAPI NtQueryValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, IN PVOID KeyValueInformation, IN ULONG Length, IN PULONG ResultLength)
DWORD WINAPI GetLongPathNameW(IN LPCWSTR lpszShortPath, OUT LPWSTR lpszLongPath, IN DWORD cchBuffer)
Definition: path.c:1455
unsigned int BOOL
Definition: ntddk_ex.h:94
#define UNICODE_STRING_MAX_CHARS
UNICODE_STRING BaseWindowsDirectory
Definition: path.c:20
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
NTSTATUS NTAPI RtlSetCurrentDirectory_U(IN PUNICODE_STRING Path)
Definition: path.c:1620
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
DWORD WINAPI GetShortPathNameW(IN LPCWSTR lpszLongPath, OUT LPWSTR lpszShortPath, IN DWORD cchBuffer)
Definition: path.c:1832
DWORD WINAPI GetShortPathNameA(IN LPCSTR lpszLongPath, OUT LPSTR lpszShortPath, IN DWORD cchBuffer)
Definition: path.c:1751
#define MAX_PATH
Definition: compat.h:26
const GLubyte * c
Definition: glext.h:8905
unsigned int UINT
Definition: ndis.h:50
DWORD IllegalMask[4]
Definition: path.c:28
NTSYSAPI VOID NTAPI RtlFreeAnsiString(PANSI_STRING AnsiString)
CHAR AnsiBuffer[1024]
Definition: debug.c:15
unsigned long DWORD
Definition: ntddk_ex.h:95
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define SetLastError(x)
Definition: compat.h:409
#define NT_ERROR(Status)
Definition: umtypes.h:106
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
BASE_CURRENT_DIR_PLACEMENT BasepDllCurrentDirPlacement
Definition: path.c:81
ULONG NTAPI RtlGetCurrentDirectory_U(_In_ ULONG MaximumLength, _Out_bytecap_(MaximumLength) PWSTR Buffer)
Definition: path.c:1542
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
unsigned char UCHAR
Definition: xmlstorage.h:181
NTSYSAPI NTSTATUS NTAPI RtlUnicodeToMultiByteN(PCHAR MbString, ULONG MbSize, PULONG ResultSize, PCWCH UnicodeString, ULONG UnicodeSize)
NTSYSAPI BOOLEAN NTAPI RtlCreateUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
DWORD FilenameW2A_FitOrFail(LPSTR DestA, INT destLen, LPCWSTR SourceW, INT sourceLen)
Definition: fileinfo.c:102
#define STATUS_VARIABLE_NOT_FOUND
Definition: ntstatus.h:478
static const WCHAR L[]
Definition: oid.c:1250
UINT WINAPI GetSystemWow64DirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2420
BOOL WINAPI SetCurrentDirectoryA(IN LPCSTR lpPathName)
Definition: path.c:2205
RTL_PATH_TYPE NTAPI RtlDetermineDosPathNameType_U(IN PCWSTR Path)
Definition: path.c:1494
NTSTATUS NTAPI LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag, IN PLDR_ENUM_CALLBACK EnumProc, IN PVOID Context)
Definition: ldrapi.c:1120
static stack_node_t temp
Definition: rpn.c:18
VOID NTAPI BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry, IN PVOID Context, OUT BOOLEAN *StopEnumeration)
Definition: utils.c:156
#define WINAPI
Definition: msvc.h:20
_In_ LPCSTR _In_opt_ LPCSTR lpExtension
Definition: winbase.h:3011
DWORD WINAPI SearchPathW(IN LPCWSTR lpPath OPTIONAL, IN LPCWSTR lpFileName, IN LPCWSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart OPTIONAL)
Definition: path.c:1297
Status
Definition: gdiplustypes.h:24
#define Dst
Definition: mesh.h:153
RTL_CRITICAL_SECTION BaseDllDirectoryLock
Definition: dllmain.c:32
LPWSTR WINAPI BaseComputeProcessDllPath(IN LPWSTR FullPath, IN PVOID Environment)
Definition: path.c:420
enum _BASE_SEARCH_PATH_TYPE * PBASE_SEARCH_PATH_TYPE
ULONG_PTR SIZE_T
Definition: typedefs.h:78
#define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a)
PRTL_UNICODE_STRING_BUFFER Path
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
_CRTIMP wchar_t *__cdecl wcsncpy(wchar_t *_Dest, const wchar_t *_Source, size_t _Count)
PRTL_COUNT_STRING BasepUnicodeStringTo8BitSize
Definition: utils.c:28
DWORD WINAPI GetTempPathA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2053
#define NtCurrentPeb()
Definition: FLS.c:19
unsigned short USHORT
Definition: pedump.c:61
BASE_SEARCH_PATH_TYPE BaseProcessOrder[BaseSearchPathMax]
Definition: path.c:72
BOOL WINAPI SetDllDirectoryW(IN LPCWSTR lpPathName)
Definition: path.c:799
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
UNICODE_STRING BaseDefaultPathAppend
Definition: path.c:21
static const char const char * DllPath
Definition: image.c:34
UNICODE_STRING BasePathVariableName
Definition: proc.c:23
BOOL WINAPI SetCurrentDirectoryW(IN LPCWSTR lpPathName)
Definition: path.c:2248
DWORD WINAPI GetCurrentDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2145
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
#define STATUS_NO_SUCH_FILE
Definition: udferr_usr.h:137
DWORD WINAPI GetDllDirectoryW(IN DWORD nBufferLength, OUT LPWSTR lpBuffer)
Definition: path.c:886
Definition: services.c:325
UINT WINAPI GetWindowsDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2336
UNICODE_STRING FullDllName
Definition: btrfs_drv.h:1807
UINT WINAPI GetSystemDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2312
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
NTSYSAPI NTSTATUS WINAPI RtlInitUnicodeStringEx(PUNICODE_STRING, PCWSTR)
#define SEM_NOOPENFILEERRORBOX
Definition: rtltypes.h:72
PRTL_CONVERT_STRING Basep8BitStringToUnicodeString
Definition: utils.c:26
VOID NTAPI RtlAcquirePebLock(VOID)
Definition: libsupp.c:72
LPWSTR WINAPI BaseComputeProcessExePath(IN LPWSTR FullPath)
Definition: path.c:405
char * strchr(const char *String, int ch)
Definition: utclib.c:501
#define UNIMPLEMENTED_DBGBREAK(...)
Definition: debug.h:57
DWORD WINAPI GetCurrentDirectoryW(IN DWORD nBufferLength, OUT LPWSTR lpBuffer)
Definition: path.c:2194
NTSYSAPI NTSTATUS NTAPI NtOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
Definition: ntapi.c:336
#define OUT
Definition: typedefs.h:39
#define c
Definition: ke_i.h:80
unsigned int ULONG
Definition: retypes.h:1
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:92
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define UNIMPLEMENTED
Definition: debug.h:114
_In_ PFCB _In_ PCD_NAME DirName
Definition: cdprocs.h:741
enum _BASE_CURRENT_DIR_PLACEMENT BASE_CURRENT_DIR_PLACEMENT
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ SECURITY_INFORMATION _In_ ULONG _Out_opt_ PULONG LengthNeeded
Definition: fltkernel.h:1342
UNICODE_STRING NoDefaultCurrentDirectoryInExePath
Definition: path.c:18
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
return STATUS_SUCCESS
Definition: btrfs.c:2725
#define GetEnvironmentVariableW(x, y, z)
Definition: compat.h:412
#define __FUNCTION__
Definition: types.h:112
#define memset(x, y, z)
Definition: compat.h:39
signed int * PLONG
Definition: retypes.h:5
BASE_SEARCH_PATH_TYPE BaseDllOrderCurrent[BaseCurrentDirPlacementMax][BaseSearchPathMax]
Definition: path.c:36
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
enum _BASE_SEARCH_PATH_TYPE BASE_SEARCH_PATH_TYPE
IN PUNICODE_STRING StaticString
LPWSTR WINAPI BasepComputeProcessPath(IN PBASE_SEARCH_PATH_TYPE PathOrder, IN LPWSTR AppName, IN LPVOID Environment)
Definition: path.c:116
_In_ LPCSTR lpFileName
Definition: winbase.h:3011
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
BASE_SEARCH_PATH_TYPE BaseDllOrderNoCurrent[BaseSearchPathMax]
Definition: path.c:63
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
UNICODE_STRING BaseWindowsSystemDirectory
Definition: path.c:20
#define ERROR_FILENAME_EXCED_RANGE
Definition: winerror.h:263
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68