mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 20:56:26 +00:00
[RTL]
- Reimplement RtlSetCurrentDirectory_U. This fixes bugs & implements references count - Fix the FIXME in RtlpDosPathNameToRelativeNtPathName_Ustr by incrementing references count svn path=/trunk/; revision=55017
This commit is contained in:
parent
823685091e
commit
f65034e760
1 changed files with 194 additions and 70 deletions
|
@ -6,6 +6,8 @@
|
||||||
* PROGRAMMERS: Wine team
|
* PROGRAMMERS: Wine team
|
||||||
* Thomas Weidenmueller
|
* Thomas Weidenmueller
|
||||||
* Gunnar Dalsnes
|
* Gunnar Dalsnes
|
||||||
|
* Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
|
* Pierre Schweitzer (pierre@reactos.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES *****************************************************************/
|
||||||
|
@ -21,6 +23,11 @@
|
||||||
|
|
||||||
#define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/'))
|
#define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/'))
|
||||||
|
|
||||||
|
#define RTL_CURDIR_IS_REMOVABLE 0x1
|
||||||
|
#define RTL_CURDIR_DROP_OLD_HANDLE 0x2
|
||||||
|
#define RTL_CURDIR_ALL_FLAGS (RTL_CURDIR_DROP_OLD_HANDLE | RTL_CURDIR_IS_REMOVABLE) // 0x3
|
||||||
|
C_ASSERT(RTL_CURDIR_ALL_FLAGS == OBJ_HANDLE_TAGBITS);
|
||||||
|
|
||||||
|
|
||||||
/* GLOBALS ********************************************************************/
|
/* GLOBALS ********************************************************************/
|
||||||
|
|
||||||
|
@ -617,7 +624,7 @@ RtlpDosPathNameToRelativeNtPathName_Ustr(IN BOOLEAN HaveRelative,
|
||||||
if (InputPathType == RtlPathTypeRelative)
|
if (InputPathType == RtlPathTypeRelative)
|
||||||
{
|
{
|
||||||
/* Get current directory */
|
/* Get current directory */
|
||||||
CurrentDirectory = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectory.DosPath);
|
CurrentDirectory = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
|
||||||
if (CurrentDirectory->Handle)
|
if (CurrentDirectory->Handle)
|
||||||
{
|
{
|
||||||
Status = RtlInitUnicodeStringEx(&FullPath, Buffer);
|
Status = RtlInitUnicodeStringEx(&FullPath, Buffer);
|
||||||
|
@ -660,7 +667,7 @@ RtlpDosPathNameToRelativeNtPathName_Ustr(IN BOOLEAN HaveRelative,
|
||||||
RelativeName->CurDirRef = RtlpCurDirRef;
|
RelativeName->CurDirRef = RtlpCurDirRef;
|
||||||
if (RelativeName->CurDirRef)
|
if (RelativeName->CurDirRef)
|
||||||
{
|
{
|
||||||
/* FIXME: Increment reference count */
|
InterlockedIncrement(&RtlpCurDirRef->RefCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
RelativeName->ContainingDirectory = CurrentDirectory->Handle;
|
RelativeName->ContainingDirectory = CurrentDirectory->Handle;
|
||||||
|
@ -831,8 +838,13 @@ RtlReleaseRelativeName(IN PRTL_RELATIVE_NAME_U RelativeName)
|
||||||
/* Check if a directory reference was grabbed */
|
/* Check if a directory reference was grabbed */
|
||||||
if (RelativeName->CurDirRef)
|
if (RelativeName->CurDirRef)
|
||||||
{
|
{
|
||||||
/* FIXME: Not yet supported */
|
/* Decrease reference count */
|
||||||
UNIMPLEMENTED;
|
if (!InterlockedDecrement(&RelativeName->CurDirRef->RefCount))
|
||||||
|
{
|
||||||
|
/* If no one uses it any longer, close handle & free */
|
||||||
|
NtClose(RelativeName->CurDirRef->Handle);
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeName->CurDirRef);
|
||||||
|
}
|
||||||
RelativeName->CurDirRef = NULL;
|
RelativeName->CurDirRef = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -984,89 +996,201 @@ RtlGetCurrentDirectory_U(IN ULONG MaximumLength,
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS NTAPI
|
NTSTATUS
|
||||||
RtlSetCurrentDirectory_U(PUNICODE_STRING dir)
|
NTAPI
|
||||||
|
RtlSetCurrentDirectory_U(IN PUNICODE_STRING Path)
|
||||||
{
|
{
|
||||||
UNICODE_STRING full;
|
PCURDIR CurDir;
|
||||||
FILE_FS_DEVICE_INFORMATION device_info;
|
|
||||||
OBJECT_ATTRIBUTES Attr;
|
|
||||||
IO_STATUS_BLOCK iosb;
|
|
||||||
PCURDIR cd;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
USHORT size;
|
RTL_PATH_TYPE PathType;
|
||||||
HANDLE handle = NULL;
|
IO_STATUS_BLOCK IoStatusBlock;
|
||||||
PWSTR ptr;
|
UNICODE_STRING FullPath, NtName;
|
||||||
|
PRTLP_CURDIR_REF OldCurDir = NULL;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
FILE_FS_DEVICE_INFORMATION FileFsDeviceInfo;
|
||||||
|
ULONG SavedLength, CharLength, FullPathLength;
|
||||||
|
HANDLE OldHandle = 0, CurDirHandle, OldCurDirHandle = 0;
|
||||||
|
|
||||||
DPRINT("RtlSetCurrentDirectory %wZ\n", dir);
|
DPRINT("RtlSetCurrentDirectory_U %wZ\n", Path);
|
||||||
|
|
||||||
full.Buffer = NULL;
|
/* Can't set current directory on DOS device */
|
||||||
|
if (RtlIsDosDeviceName_Ustr(Path))
|
||||||
RtlAcquirePebLock ();
|
|
||||||
|
|
||||||
cd = (PCURDIR)&NtCurrentPeb ()->ProcessParameters->CurrentDirectory.DosPath;
|
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U (dir->Buffer, &full, 0, 0))
|
|
||||||
{
|
{
|
||||||
RtlReleasePebLock ();
|
return STATUS_NOT_A_DIRECTORY;
|
||||||
return STATUS_OBJECT_NAME_INVALID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT("RtlSetCurrentDirectory: full %wZ\n",&full);
|
/* Get current directory */
|
||||||
|
RtlAcquirePebLock();
|
||||||
|
CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory;
|
||||||
|
|
||||||
InitializeObjectAttributes (&Attr,
|
/* Check if we have to drop current handle */
|
||||||
&full,
|
if (((ULONG_PTR)(CurDir->Handle) & RTL_CURDIR_ALL_FLAGS) == RTL_CURDIR_DROP_OLD_HANDLE)
|
||||||
|
{
|
||||||
|
OldHandle = CurDir->Handle;
|
||||||
|
CurDir->Handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a buffer for full path (using max possible length */
|
||||||
|
FullPath.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, CurDir->DosPath.MaximumLength);
|
||||||
|
if (!FullPath.Buffer)
|
||||||
|
{
|
||||||
|
Status = STATUS_NO_MEMORY;
|
||||||
|
goto Leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init string */
|
||||||
|
FullPath.Length = 0;
|
||||||
|
FullPath.MaximumLength = CurDir->DosPath.MaximumLength;
|
||||||
|
|
||||||
|
/* Get new directory full path */
|
||||||
|
FullPathLength = RtlGetFullPathName_Ustr(Path, FullPath.MaximumLength, FullPath.Buffer, NULL, NULL, &PathType);
|
||||||
|
if (!FullPathLength)
|
||||||
|
{
|
||||||
|
Status = STATUS_OBJECT_NAME_INVALID;
|
||||||
|
goto Leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
SavedLength = FullPath.MaximumLength;
|
||||||
|
CharLength = FullPathLength / sizeof(WCHAR);
|
||||||
|
|
||||||
|
if (FullPathLength > FullPath.MaximumLength)
|
||||||
|
{
|
||||||
|
Status = STATUS_NAME_TOO_LONG;
|
||||||
|
goto Leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Translate it to NT name */
|
||||||
|
if (!RtlDosPathNameToNtPathName_U(FullPath.Buffer, &NtName, NULL, NULL))
|
||||||
|
{
|
||||||
|
Status = STATUS_OBJECT_NAME_INVALID;
|
||||||
|
goto Leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, &NtName,
|
||||||
OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
|
OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
|
||||||
NULL,
|
NULL, NULL);
|
||||||
NULL);
|
|
||||||
|
|
||||||
Status = ZwOpenFile (&handle,
|
/* If previous current directory was removable, then check it for dropping */
|
||||||
SYNCHRONIZE | FILE_TRAVERSE,
|
if (((ULONG_PTR)(CurDir->Handle) & RTL_CURDIR_ALL_FLAGS) == RTL_CURDIR_ALL_FLAGS)
|
||||||
&Attr,
|
{
|
||||||
&iosb,
|
/* Get back normal handle */
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
CurDirHandle = (HANDLE)((ULONG_PTR)(CurDir->Handle) & ~RTL_CURDIR_ALL_FLAGS);
|
||||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
|
CurDir->Handle = 0;
|
||||||
|
|
||||||
|
/* Get device information */
|
||||||
|
Status = NtQueryVolumeInformationFile(CurDirHandle,
|
||||||
|
&IoStatusBlock,
|
||||||
|
&FileFsDeviceInfo,
|
||||||
|
sizeof(FileFsDeviceInfo),
|
||||||
|
FileFsDeviceInformation);
|
||||||
|
/* Retry without taking care of removable device */
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
RtlFreeUnicodeString( &full);
|
Status = RtlSetCurrentDirectory_U(Path);
|
||||||
RtlReleasePebLock ();
|
goto Leave;
|
||||||
return Status;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* don't keep the directory handle open on removable media */
|
else
|
||||||
if (NT_SUCCESS(ZwQueryVolumeInformationFile( handle, &iosb, &device_info,
|
|
||||||
sizeof(device_info), FileFsDeviceInformation )) &&
|
|
||||||
(device_info.Characteristics & FILE_REMOVABLE_MEDIA))
|
|
||||||
{
|
{
|
||||||
DPRINT1("don't keep the directory handle open on removable media\n");
|
/* Open directory */
|
||||||
ZwClose( handle );
|
Status = NtOpenFile(&CurDirHandle,
|
||||||
handle = 0;
|
SYNCHRONIZE | FILE_TRAVERSE,
|
||||||
|
&ObjectAttributes,
|
||||||
|
&IoStatusBlock,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
|
||||||
|
if (!NT_SUCCESS(Status)) goto Leave;
|
||||||
|
|
||||||
|
/* Get device information */
|
||||||
|
Status = NtQueryVolumeInformationFile(CurDirHandle,
|
||||||
|
&IoStatusBlock,
|
||||||
|
&FileFsDeviceInfo,
|
||||||
|
sizeof(FileFsDeviceInfo),
|
||||||
|
FileFsDeviceInformation);
|
||||||
|
if (!NT_SUCCESS(Status)) goto Leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cd->Handle)
|
/* If device is removable, mark handle */
|
||||||
ZwClose(cd->Handle);
|
if (FileFsDeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA)
|
||||||
cd->Handle = handle;
|
{
|
||||||
|
CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_CURDIR_IS_REMOVABLE);
|
||||||
|
}
|
||||||
|
|
||||||
/* append trailing \ if missing */
|
FullPath.Length = FullPathLength;
|
||||||
size = full.Length / sizeof(WCHAR);
|
|
||||||
ptr = full.Buffer;
|
|
||||||
ptr += 4; /* skip \??\ prefix */
|
|
||||||
size -= 4;
|
|
||||||
|
|
||||||
/* This is ok because RtlDosPathNameToNtPathName_U returns a nullterminated string.
|
/* If full path isn't \ terminated, do it */
|
||||||
* So the nullterm is replaced with \
|
if (FullPath.Buffer[CharLength - 1] != L'\\')
|
||||||
* -Gunnar
|
{
|
||||||
*/
|
if ((CharLength + 1) * sizeof(WCHAR) > SavedLength)
|
||||||
if (size && ptr[size - 1] != '\\') ptr[size++] = '\\';
|
{
|
||||||
|
Status = STATUS_NAME_TOO_LONG;
|
||||||
|
goto Leave;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy( cd->DosPath.Buffer, ptr, size * sizeof(WCHAR));
|
FullPath.Buffer[CharLength] = L'\\';
|
||||||
cd->DosPath.Buffer[size] = 0;
|
FullPath.Buffer[CharLength + 1] = UNICODE_NULL;
|
||||||
cd->DosPath.Length = size * sizeof(WCHAR);
|
FullPath.Length += sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
RtlFreeUnicodeString( &full);
|
/* If we have previous current directory with only us as reference, save it */
|
||||||
|
if (RtlpCurDirRef != NULL && RtlpCurDirRef->RefCount == 1)
|
||||||
|
{
|
||||||
|
OldCurDirHandle = RtlpCurDirRef->Handle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Allocate new current directory struct saving previous one */
|
||||||
|
OldCurDir = RtlpCurDirRef;
|
||||||
|
RtlpCurDirRef = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTLP_CURDIR_REF));
|
||||||
|
if (!RtlpCurDirRef)
|
||||||
|
{
|
||||||
|
RtlpCurDirRef = OldCurDir;
|
||||||
|
OldCurDir = NULL;
|
||||||
|
Status = STATUS_NO_MEMORY;
|
||||||
|
goto Leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set reference to 1 (us) */
|
||||||
|
RtlpCurDirRef->RefCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save new data */
|
||||||
|
CurDir->Handle = CurDirHandle;
|
||||||
|
RtlpCurDirRef->Handle = CurDirHandle;
|
||||||
|
CurDirHandle = 0;
|
||||||
|
|
||||||
|
/* Copy full path */
|
||||||
|
RtlCopyMemory(CurDir->DosPath.Buffer, FullPath.Buffer, FullPath.Length + sizeof(WCHAR));
|
||||||
|
CurDir->DosPath.Length = FullPath.Length;
|
||||||
|
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
Leave:
|
||||||
RtlReleasePebLock();
|
RtlReleasePebLock();
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
if (FullPath.Buffer)
|
||||||
|
{
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, FullPath.Buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NtName.Buffer)
|
||||||
|
{
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, NtName.Buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurDirHandle) NtClose(CurDirHandle);
|
||||||
|
|
||||||
|
if (OldHandle) NtClose(OldHandle);
|
||||||
|
|
||||||
|
if (OldCurDirHandle) NtClose(OldCurDirHandle);
|
||||||
|
|
||||||
|
if (OldCurDir && InterlockedDecrement(&OldCurDir->RefCount) == 0)
|
||||||
|
{
|
||||||
|
NtClose(OldCurDir->Handle);
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, OldCurDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue