3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/ntdll/rtl/path.c
6 * PURPOSE: Path and current directory functions
11 /* INCLUDES ******************************************************************/
13 #include <ddk/ntddk.h>
14 #include <ntdll/rtl.h>
18 #include <ddk/obfuncs.h>
21 #include <ntdll/ntdll.h>
23 /* DEFINITONS and MACROS ******************************************************/
25 #define MAX_PFX_SIZE 16
27 #define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/'))
30 /* FUNCTIONS *****************************************************************/
32 static ULONG RtlpGetDotSequence (PWSTR p)
40 else if ((*p == '\\' || *p == '\0') && Count)
50 static VOID RtlpEatPath (PWSTR Path)
57 while ((*p) != 0 || ((*p) == L'\\' && (*(p+1)) == 0))
61 DotLen = RtlpGetDotSequence (p+1);
62 DPRINT("DotSequenceLength %u\n", DotLen);
63 DPRINT("prev %S p %S\n",prev,p);
72 while ((*p) != 0 && (*p) != L'\\');
84 while (n > 0 && prev > (Path + 2))
92 if (*(p + DotLen + 1) == 0)
95 wcscpy (prev, p + DotLen + 1);
97 if (prev > (Path + 2))
100 while ((*prev) != L'\\')
115 ULONG STDCALL RtlGetLongestNtPathLength (VOID)
117 return (MAX_PATH + 9);
122 RtlDetermineDosPathNameType_U(PWSTR Path)
124 DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
131 if (IS_PATH_SEPARATOR(Path[0]))
133 if (!IS_PATH_SEPARATOR(Path[1]))
139 return 1; /* \\xxx */
141 if (IS_PATH_SEPARATOR(Path[3]))
142 return 6; /* \\.\xxx */
145 return 1; /* \\.xxxx */
154 if (IS_PATH_SEPARATOR(Path[2]))
155 return 2; /* x:\xxx */
157 return 3; /* x:xxx */
162 /* returns 0 if name is not valid DOS device name, or DWORD with
163 * offset in bytes to DOS device name from beginning of buffer in high word
164 * and size in bytes of DOS device name in low word */
167 RtlIsDosDeviceName_U(PWSTR DeviceName)
174 if (DeviceName == NULL)
179 while (DeviceName[Length])
184 Type = RtlDetermineDosPathNameType_U(DeviceName);
193 !_wcsnicmp (DeviceName, L"\\\\.\\CON", 7))
198 /* name can end with ':' */
199 if (Length && DeviceName[Length - 1 ] == L':')
204 /* there can be spaces or points at the end of name */
205 wc = DeviceName + Length - 1;
206 while (Length && (*wc == L'.' || *wc == L' '))
212 /* let's find a beginning of name */
213 wc = DeviceName + Length - 1;
214 while (wc > DeviceName && !IS_PATH_SEPARATOR(*(wc - 1)))
218 Offset = wc - DeviceName;
221 /* check for LPTx or COMx */
222 if (Length == 4 && wc[3] >= L'0' && wc[3] <= L'9')
229 if (!_wcsnicmp (wc, L"LPT", 3) ||
230 !_wcsnicmp (wc, L"COM", 3))
232 return ((Offset * 2) << 16 ) | 8;
237 /* check for PRN,AUX,NUL or CON */
239 (!_wcsnicmp (wc, L"PRN", 3) ||
240 !_wcsnicmp (wc, L"AUX", 3) ||
241 !_wcsnicmp (wc, L"NUL", 3) ||
242 !_wcsnicmp (wc, L"CON", 3)))
244 return ((Offset * 2) << 16) | 6;
252 RtlGetCurrentDirectory_U(ULONG MaximumLength,
258 DPRINT ("RtlGetCurrentDirectory %lu %p\n", MaximumLength, Buffer);
262 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName);
263 Length = cd->DosPath.Length / sizeof(WCHAR);
264 if (cd->DosPath.Buffer[Length - 1] == L'\\' &&
265 cd->DosPath.Buffer[Length - 2] != L':')
268 DPRINT ("cd->DosPath.Buffer %S Length %d\n",
269 cd->DosPath.Buffer, Length);
271 if (MaximumLength / sizeof(WCHAR) > Length)
275 Length * sizeof(WCHAR));
283 RtlReleasePebLock ();
285 DPRINT ("CurrentDirectory %S\n", Buffer);
287 return (Length * sizeof(WCHAR));
292 RtlSetCurrentDirectory_U(PUNICODE_STRING name)
295 UNICODE_STRING envvar;
296 OBJECT_ATTRIBUTES Attr;
297 IO_STATUS_BLOCK iosb;
301 HANDLE handle = NULL;
304 PFILE_NAME_INFORMATION filenameinfo;
305 ULONG backslashcount = 0;
309 DPRINT ("RtlSetCurrentDirectory %wZ\n", name);
311 RtlAcquirePebLock ();
312 cd = (PCURDIR)&NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName;
313 size = cd->DosPath.MaximumLength;
315 buf = RtlAllocateHeap (RtlGetProcessHeap(),
320 RtlReleasePebLock ();
321 return STATUS_NO_MEMORY;
324 size = RtlGetFullPathName_U (name->Buffer, size, buf, 0);
327 RtlFreeHeap (RtlGetProcessHeap (),
330 RtlReleasePebLock ();
331 return STATUS_OBJECT_NAME_INVALID;
334 if (!RtlDosPathNameToNtPathName_U (buf, &full, 0, 0))
336 RtlFreeHeap (RtlGetProcessHeap (),
339 RtlFreeHeap (RtlGetProcessHeap (),
342 RtlReleasePebLock ();
343 return STATUS_OBJECT_NAME_INVALID;
346 InitializeObjectAttributes (&Attr,
348 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
352 Status = NtOpenFile (&handle,
353 SYNCHRONIZE | FILE_TRAVERSE,
356 FILE_SHARE_READ | FILE_SHARE_WRITE,
357 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
358 if (!NT_SUCCESS(Status))
360 RtlFreeHeap (RtlGetProcessHeap (),
363 RtlFreeHeap (RtlGetProcessHeap (),
366 RtlReleasePebLock ();
370 filenameinfo = RtlAllocateHeap(RtlGetProcessHeap(),
372 MAX_PATH*sizeof(WCHAR)+sizeof(ULONG));
374 Status = NtQueryInformationFile(handle,
377 MAX_PATH*sizeof(WCHAR)+sizeof(ULONG),
378 FileNameInformation);
379 if (!NT_SUCCESS(Status))
381 RtlFreeHeap(RtlGetProcessHeap(),
384 RtlFreeHeap(RtlGetProcessHeap(),
387 RtlFreeHeap(RtlGetProcessHeap(),
394 if (filenameinfo->FileName[1]) // If it's just "\", we need special handling
396 wcs = buf + size / sizeof(WCHAR) - 1;
401 size -= sizeof(WCHAR);
404 for (cntr=filenameinfo->FileName;*cntr!=0;cntr++)
406 if (*cntr=='\\') backslashcount++;
409 DPRINT("%d \n",backslashcount);
410 for (;backslashcount;wcs--)
412 if (*wcs=='\\') backslashcount--;
416 wcscpy(wcs,filenameinfo->FileName);
418 size=((wcs-buf)+wcslen(filenameinfo->FileName))*sizeof(WCHAR);
421 RtlFreeHeap (RtlGetProcessHeap (),
425 /* append backslash if missing */
426 wcs = buf + size / sizeof(WCHAR) - 1;
431 size += sizeof(WCHAR);
434 memmove(cd->DosPath.Buffer,
436 size + sizeof(WCHAR));
437 cd->DosPath.Length = size;
443 if (cd->DosPath.Buffer[1]==':')
445 envvar.Length = 2 * swprintf (var, L"=%c:", cd->DosPath.Buffer[0]);
446 envvar.MaximumLength = 8;
449 RtlSetEnvironmentVariable(NULL,
454 RtlFreeHeap (RtlGetProcessHeap (),
458 RtlFreeHeap (RtlGetProcessHeap (),
464 return STATUS_SUCCESS;
469 RtlGetFullPathName_U(PWSTR DosName,
474 WCHAR *wcs, var[4], drive;
477 DWORD offs, sz, type;
478 UNICODE_STRING usvar, pfx;
482 DPRINT("RtlGetFullPathName_U %S %ld %p %p\n",
483 DosName, size, buf, FilePart);
485 if (!DosName || !*DosName)
488 len = wcslen (DosName);
490 /* strip trailing spaces */
491 while (len && DosName[len - 1] == L' ')
497 /* strip trailing path separator (but don't change '\') */
499 IS_PATH_SEPARATOR(DosName[len - 1]))
503 memset (buf, 0, size);
506 /* check for DOS device name */
507 sz = RtlIsDosDeviceName_U (DosName);
514 wcscpy (buf, L"\\\\.\\");
515 wcsncat (buf, DosName + offs, sz / sizeof(WCHAR));
520 type = RtlDetermineDosPathNameType_U (DosName);
524 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName);
525 DPRINT("type %ld\n", type);
528 case 1: /* \\xxx or \\.xxx */
529 case 6: /* \\.\xxx */
533 *DosName = towupper (*DosName);
537 drive = towupper (*DosName);
541 if (drive == towupper (cd->DosPath.Buffer[0]))
544 wcscpy (buf, cd->DosPath.Buffer);
549 usvar.Length = 2 * swprintf (var, L"=%c:", drive);
550 usvar.MaximumLength = 8;
553 pfx.MaximumLength = size;
555 Status = RtlQueryEnvironmentVariable_U (NULL,
559 if (!NT_SUCCESS(Status))
562 if (Status == STATUS_BUFFER_TOO_SMALL)
563 return pfx.Length + len * 2 + 2;
564 swprintf (buf, L"%c:\\", drive);
570 wcsncpy (buf, cd->DosPath.Buffer, 2);
574 wcscpy (buf, cd->DosPath.Buffer);
578 wcscpy (buf, L"\\\\.\\");
586 DPRINT("buf \'%S\' DosName \'%S\' len %ld\n", buf, DosName, len);
587 /* add dosname to prefix */
588 wcsncat (buf, DosName, len);
591 /* replace slashes */
592 for (wcs = buf; *wcs; wcs++)
597 if (len < 3 && buf[len-1] == L':')
600 DPRINT("buf \'%S\'\n", buf);
602 DPRINT("buf \'%S\'\n", buf);
609 for (wcs = buf + len - 1; wcs >= buf; wcs--)
621 return len * sizeof(WCHAR);
626 RtlDosPathNameToNtPathName_U(PWSTR dosname,
627 PUNICODE_STRING ntname,
637 WCHAR fullname[2*MAX_PATH];
640 RtlAcquirePebLock ();
642 RtlInitUnicodeString (&us, dosname);
646 /* check for "\\?\" - allows to use very long filenames ( up to 32k ) */
647 if (Buffer[0] == L'\\' && Buffer[1] == L'\\' &&
648 Buffer[2] == L'?' && Buffer[3] == L'\\')
650 // if( f_77F68606( &us, ntname, shortname, nah ) )
652 // RtlReleasePebLock ();
656 RtlReleasePebLock ();
661 Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
663 sizeof( fullname ) + MAX_PFX_SIZE);
666 RtlReleasePebLock ();
670 Size = RtlGetFullPathName_U (dosname,
674 if (Size == 0 || Size > MAX_PATH * sizeof(WCHAR))
676 RtlFreeHeap (RtlGetProcessHeap (),
679 RtlReleasePebLock ();
685 wcscpy (Buffer, L"\\??\\");
687 Type = RtlDetermineDosPathNameType_U (fullname);
691 wcscat (Buffer, L"UNC\\");
699 wcscat (Buffer, fullname + Offset);
700 Length = wcslen (Buffer);
702 /* set NT filename */
703 ntname->Length = Length * sizeof(WCHAR);
704 ntname->MaximumLength = sizeof(fullname) + MAX_PFX_SIZE;
705 ntname->Buffer = Buffer;
707 /* set pointer to file part if possible */
708 if (FilePart && *FilePart)
709 *FilePart = Buffer + Length - wcslen (*FilePart);
711 /* Set name and handle structure if possible */
714 memset (nah, 0, sizeof(CURDIR));
715 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName);
716 if (Type == 5 && cd->Handle &&
717 !_wcsnicmp (cd->DosPath.Buffer, fullname, cd->DosPath.Length / 2))
719 Length = ((cd->DosPath.Length / sizeof(WCHAR)) - Offset) + ((Type == 1) ? 8 : 4);
720 nah->DosPath.Buffer = Buffer + Length;
721 nah->DosPath.Length = ntname->Length - (Length * sizeof(WCHAR));
722 nah->DosPath.MaximumLength = nah->DosPath.Length;
723 nah->Handle = cd->Handle;
750 Type = RtlDetermineDosPathNameType_U (name);
754 Length = wcslen (sp);
755 Length += wcslen (name);
756 if (wcschr (name, L'.'))
759 Length += wcslen (ext);
761 full_name = (WCHAR*)RtlAllocateHeap (RtlGetProcessHeap (),
763 (Length + 1) * sizeof(WCHAR));
765 if (full_name != NULL)
771 while (*path && *path != L';')
775 if (wcs != full_name && *(wcs - 1) != L'\\')
780 if (RtlDoesFileExists_U (full_name))
782 Length = RtlGetFullPathName_U (full_name,
790 RtlFreeHeap (RtlGetProcessHeap (),
795 else if (RtlDoesFileExists_U (name))
797 Length = RtlGetFullPathName_U (name,
808 RtlDoesFileExists_U(IN PWSTR FileName)
810 UNICODE_STRING NtFileName;
811 OBJECT_ATTRIBUTES Attr;
816 /* only used by replacement code */
818 IO_STATUS_BLOCK StatusBlock;
820 if (!RtlDosPathNameToNtPathName_U (FileName,
826 /* don't forget to free it! */
827 Buffer = NtFileName.Buffer;
829 if (CurDir.DosPath.Length)
830 NtFileName = CurDir.DosPath;
834 InitializeObjectAttributes (&Attr,
836 OBJ_CASE_INSENSITIVE,
840 /* FIXME: not implemented yet */
841 // Status = NtQueryAttributesFile (&Attr, NULL);
843 /* REPLACEMENT start */
844 Status = NtOpenFile (&FileHandle,
849 FILE_SYNCHRONOUS_IO_NONALERT);
850 if (NT_SUCCESS(Status))
851 NtClose (FileHandle);
852 /* REPLACEMENT end */
854 RtlFreeHeap (RtlGetProcessHeap (),
858 if (NT_SUCCESS(Status) ||
859 Status == STATUS_SHARING_VIOLATION ||
860 Status == STATUS_ACCESS_DENIED)