https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f6eb13a969e5108f0e58b…
commit f6eb13a969e5108f0e58bc71473f04ab4dce399f
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Tue Jun 11 21:18:22 2019 +0200
Commit: Pierre Schweitzer <pierre(a)reactos.org>
CommitDate: Tue Jun 11 21:21:52 2019 +0200
[NTOSKRNL] Rework ObpDeleteSymbolicLinkName and ObpCreateSymbolicLinkName
So that they handle LUID mappings and process device maps.
Get rid of the ObpParseSymbolicLinkToIoDeviceObject helper and introduce a
new helper ObpProcessDosDeviceSymbolicLink that will do the same things
but also handle name creation/deletion as well as device map handling.
All this is based on previous code (hence the same comments :-)).
What's left to do now is to add support for device maps in ObpLookupObjectName
---
ntoskrnl/ob/oblink.c | 499 +++++++++++++++++++++++++++++----------------------
1 file changed, 283 insertions(+), 216 deletions(-)
diff --git a/ntoskrnl/ob/oblink.c b/ntoskrnl/ob/oblink.c
index f8fbe5ad500..712143e1ed7 100644
--- a/ntoskrnl/ob/oblink.c
+++ b/ntoskrnl/ob/oblink.c
@@ -20,288 +20,355 @@ POBJECT_TYPE ObpSymbolicLinkObjectType = NULL;
/* PRIVATE FUNCTIONS *********************************************************/
VOID
-NTAPI
-ObpDeleteSymbolicLinkName(IN POBJECT_SYMBOLIC_LINK SymbolicLink)
+ObpProcessDosDeviceSymbolicLink(IN POBJECT_SYMBOLIC_LINK SymbolicLink,
+ IN BOOLEAN DeleteLink)
{
+ PDEVICE_MAP DeviceMap;
+ UNICODE_STRING TargetPath, LocalTarget;
+ POBJECT_DIRECTORY NameDirectory, DirectoryObject;
+ ULONG MaxReparse;
+ OBP_LOOKUP_CONTEXT LookupContext;
+ ULONG DriveType;
POBJECT_HEADER ObjectHeader;
POBJECT_HEADER_NAME_INFO ObjectNameInfo;
+ BOOLEAN DirectoryLocked;
+ PVOID Object;
- /* FIXME: Need to support Device maps */
+ /*
+ * To prevent endless reparsing, setting an upper limit on the
+ * number of reparses.
+ */
+ MaxReparse = 32;
+ NameDirectory = NULL;
/* Get header data */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink);
- ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
-
- /* Check if we are not actually in a directory with a device map */
- if (!(ObjectNameInfo) ||
- !(ObjectNameInfo->Directory) /*||
- !(ObjectNameInfo->Directory->DeviceMap)*/)
- {
- ObpDereferenceNameInfo(ObjectNameInfo);
- return;
- }
+ ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
- /* Check if it's a DOS drive letter, and remove the entry from drive map if needed */
- if (SymbolicLink->DosDeviceDriveIndex != 0 &&
- ObjectNameInfo->Name.Length == 2 * sizeof(WCHAR) &&
- ObjectNameInfo->Name.Buffer[1] == L':' &&
- ( (ObjectNameInfo->Name.Buffer[0] >= L'A' &&
- ObjectNameInfo->Name.Buffer[0] <= L'Z') ||
- (ObjectNameInfo->Name.Buffer[0] >= L'a' &&
- ObjectNameInfo->Name.Buffer[0] <= L'z') ))
+ /* Check if we have a directory in our symlink to use */
+ if (ObjectNameInfo != NULL)
{
- /* Remove the drive entry */
- KeAcquireGuardedMutex(&ObpDeviceMapLock);
- ObSystemDeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex-1] =
- DOSDEVICE_DRIVE_UNKNOWN;
- ObSystemDeviceMap->DriveMap &=
- ~(1 << (SymbolicLink->DosDeviceDriveIndex-1));
- KeReleaseGuardedMutex(&ObpDeviceMapLock);
-
- /* Reset the drive index, valid drive index starts from 1 */
- SymbolicLink->DosDeviceDriveIndex = 0;
+ NameDirectory = ObjectNameInfo->Directory;
}
- ObpDereferenceNameInfo(ObjectNameInfo);
-}
-
-NTSTATUS
-NTAPI
-ObpParseSymbolicLinkToIoDeviceObject(IN POBJECT_DIRECTORY SymbolicLinkDirectory,
- IN OUT POBJECT_DIRECTORY *Directory,
- IN OUT PUNICODE_STRING TargetPath,
- IN OUT POBP_LOOKUP_CONTEXT Context,
- OUT PVOID *Object)
-{
- UNICODE_STRING Name;
- BOOLEAN ManualUnlock;
+ /* Initialize lookup context */
+ ObpInitializeLookupContext(&LookupContext);
- if (! TargetPath || ! Object || ! Context || ! Directory ||
- ! SymbolicLinkDirectory)
+ /*
+ * If we have to create the link, locate the IoDeviceObject if any
+ * this symbolic link points to.
+ */
+ if (SymbolicLink->LinkTargetObject != NULL || !DeleteLink)
{
- return STATUS_INVALID_PARAMETER;
- }
+ /* Start the search from the root */
+ DirectoryObject = ObpRootDirectoryObject;
- /* FIXME: Need to support Device maps */
+ /* Keep track of our progress while parsing the name */
+ LocalTarget = SymbolicLink->LinkTarget;
- /* Try walking the target path and open each part of the path */
- while (TargetPath->Length)
- {
- /* Strip '\' if present at the beginning of the target path */
- if (TargetPath->Length >= sizeof(OBJ_NAME_PATH_SEPARATOR)&&
- TargetPath->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
+ /* If LUID mappings are enabled, use system map */
+ if (ObpLUIDDeviceMapsEnabled != 0)
+ {
+ DeviceMap = ObSystemDeviceMap;
+ }
+ /* Otherwise, use the one in the process */
+ else
{
- TargetPath->Buffer++;
- TargetPath->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
+ DeviceMap = PsGetCurrentProcess()->DeviceMap;
}
- /* Remember the current component of the target path */
- Name = *TargetPath;
+ReparseTargetPath:
+ /*
+ * If we have a device map active, check whether we have a drive
+ * letter prefixed with ??, if so, chomp it
+ */
+ if (DeviceMap != NULL)
+ {
+ if (!((ULONG_PTR)(LocalTarget.Buffer) & 7))
+ {
+ if (DeviceMap->DosDevicesDirectory != NULL)
+ {
+ if (LocalTarget.Length >= ObpDosDevicesShortName.Length &&
+ (*(PULONGLONG)LocalTarget.Buffer ==
+ ObpDosDevicesShortNamePrefix.Alignment.QuadPart))
+ {
+ DirectoryObject = DeviceMap->DosDevicesDirectory;
+
+ LocalTarget.Length -= ObpDosDevicesShortName.Length;
+ LocalTarget.Buffer += (ObpDosDevicesShortName.Length / sizeof(WCHAR));
+ }
+ }
+ }
+ }
- /* Move forward to the next component of the target path */
- while (TargetPath->Length >= sizeof(OBJ_NAME_PATH_SEPARATOR))
+ /* Try walking the target path and open each part of the path */
+ while (TRUE)
{
- if (TargetPath->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)
+ if (LocalTarget.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
{
- TargetPath->Buffer++;
- TargetPath->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
+ ++LocalTarget.Buffer;
+ LocalTarget.Length -= sizeof(WCHAR);
+ }
+
+ /* Remember the current component of the target path */
+ TargetPath = LocalTarget;
+
+ /* Move forward to the next component of the target path */
+ if (LocalTarget.Length != 0)
+ {
+ do
+ {
+ if (LocalTarget.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
+ {
+ break;
+ }
+
+ ++LocalTarget.Buffer;
+ LocalTarget.Length -= sizeof(WCHAR);
+ }
+ while (LocalTarget.Length != 0);
+ }
+
+ TargetPath.Length -= LocalTarget.Length;
+
+ /*
+ * Finished processing the entire path, stop
+ * That's a failure case, we quit here
+ */
+ if (TargetPath.Length == 0)
+ {
+ ObpReleaseLookupContext(&LookupContext);
+ return;
+ }
+
+
+ /*
+ * Make sure a deadlock does not occur as an exclusive lock on a pushlock
+ * would have already taken one in ObpLookupObjectName() on the parent
+ * directory where the symlink is being created [ObInsertObject()].
+ * Prevent recursive locking by faking lock state in the lookup context
+ * when the current directory is same as the parent directory where
+ * the symlink is being created. If the lock state is not faked,
+ * ObpLookupEntryDirectory() will try to get a recursive lock on the
+ * pushlock and hang. For e.g. this happens when a substed drive is pointed to
+ * another substed drive.
+ */
+ if (DirectoryObject == NameDirectory)
+ {
+ DirectoryLocked = LookupContext.DirectoryLocked;
+ LookupContext.DirectoryLocked = TRUE;
}
else
+ {
+ DirectoryLocked = FALSE;
+ }
+
+ Object = ObpLookupEntryDirectory(DirectoryObject,
+ &TargetPath,
+ 0,
+ FALSE,
+ &LookupContext);
+
+ /* Locking was faked, undo it now */
+ if (DirectoryObject == NameDirectory)
+ {
+ LookupContext.DirectoryLocked = DirectoryLocked;
+ }
+
+ /* Lookup failed, stop */
+ if (Object == NULL)
+ {
break;
+ }
+
+ /* If we don't have a directory object, we'll have to handle the object */
+ if (OBJECT_TO_OBJECT_HEADER(Object)->Type != ObpDirectoryObjectType)
+ {
+ /* If that's not a symbolic link, stop here, nothing to do */
+ if (OBJECT_TO_OBJECT_HEADER(Object)->Type != ObpSymbolicLinkObjectType ||
+ (((POBJECT_SYMBOLIC_LINK)Object)->DosDeviceDriveIndex != 0))
+ {
+ break;
+ }
+
+ /* We're out of reparse attempts */
+ if (MaxReparse == 0)
+ {
+ Object = NULL;
+ break;
+ }
+
+ --MaxReparse;
+
+ /* Symlink points to another initialized symlink, ask caller to reparse */
+ DirectoryObject = ObpRootDirectoryObject;
+
+ LocalTarget = ((POBJECT_SYMBOLIC_LINK)Object)->LinkTarget;
+
+ goto ReparseTargetPath;
+ }
+
+ /* Make this current directory, and continue search */
+ DirectoryObject = Object;
}
+ }
- Name.Length -= TargetPath->Length;
+ DeviceMap = NULL;
+ /* That's a drive letter, find a suitable device map */
+ if (SymbolicLink->DosDeviceDriveIndex != 0)
+ {
+ ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink);
+ ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
+ if (ObjectNameInfo != NULL)
+ {
+ if (ObjectNameInfo->Directory != NULL)
+ {
+ DeviceMap = ObjectNameInfo->Directory->DeviceMap;
+ }
- /* Finished processing the entire path, stop */
- if (! Name.Length)
- break;
+ ObpDereferenceNameInfo(ObjectNameInfo);
+ }
+ }
- /*
- * Make sure a deadlock does not occur as an exclusive lock on a pushlock
- * would have already taken one in ObpLookupObjectName() on the parent
- * directory where the symlink is being created [ObInsertObject()].
- * Prevent recursive locking by faking lock state in the lookup context
- * when the current directory is same as the parent directory where
- * the symlink is being created. If the lock state is not faked,
- * ObpLookupEntryDirectory() will try to get a recursive lock on the
- * pushlock and hang. For e.g. this happens when a substed drive is pointed to
- * another substed drive.
- */
- if (*Directory == SymbolicLinkDirectory && ! Context->DirectoryLocked)
+ /* If we were asked to delete the symlink */
+ if (DeleteLink)
+ {
+ /* Zero its target */
+ RtlInitUnicodeString(&SymbolicLink->LinkTargetRemaining, NULL);
+
+ /* If we had a target objected, dereference it */
+ if (SymbolicLink->LinkTargetObject != NULL)
{
- /* Fake lock state so that ObpLookupEntryDirectory() doesn't attempt a lock */
- ManualUnlock = TRUE;
- Context->DirectoryLocked = TRUE;
+ ObDereferenceObject(SymbolicLink->LinkTargetObject);
+ SymbolicLink->LinkTargetObject = NULL;
}
- else
- ManualUnlock = FALSE;
- *Object = ObpLookupEntryDirectory(*Directory,
- &Name,
- 0,
- FALSE,
- Context);
+ /* If it was a drive letter */
+ if (DeviceMap != NULL)
+ {
+ /* Acquire the device map lock */
+ KeAcquireGuardedMutex(&ObpDeviceMapLock);
- /* Locking was faked, undo it now */
- if (*Directory == SymbolicLinkDirectory && ManualUnlock)
- Context->DirectoryLocked = FALSE;
+ /* Remove the drive entry */
+ DeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex - 1] =
+ DOSDEVICE_DRIVE_UNKNOWN;
+ DeviceMap->DriveMap &=
+ ~(1 << (SymbolicLink->DosDeviceDriveIndex - 1));
- /* Lookup failed, stop */
- if (! *Object)
- break;
+ /* Release the device map lock */
+ KeReleaseGuardedMutex(&ObpDeviceMapLock);
- if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObpDirectoryObjectType)
- {
- /* Make this current directory, and continue search */
- *Directory = (POBJECT_DIRECTORY)*Object;
+ /* Reset the drive index, valid drive index starts from 1 */
+ SymbolicLink->DosDeviceDriveIndex = 0;
}
- else if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObpSymbolicLinkObjectType &&
- (((POBJECT_SYMBOLIC_LINK)*Object)->DosDeviceDriveIndex == 0))
+ }
+ else
+ {
+ DriveType = DOSDEVICE_DRIVE_CALCULATE;
+
+ /* If we have a drive letter and a pointer device object */
+ if (Object != NULL && SymbolicLink->DosDeviceDriveIndex != 0 &&
+ OBJECT_TO_OBJECT_HEADER(Object)->Type == IoDeviceObjectType)
{
- /* Symlink points to another initialized symlink, ask caller to reparse */
- *Directory = ObpRootDirectoryObject;
- TargetPath = &((POBJECT_SYMBOLIC_LINK)*Object)->LinkTarget;
- return STATUS_REPARSE_OBJECT;
+ /* Calculate the drive type */
+ switch(((PDEVICE_OBJECT)Object)->DeviceType)
+ {
+ case FILE_DEVICE_VIRTUAL_DISK:
+ DriveType = DOSDEVICE_DRIVE_RAMDISK;
+ break;
+ case FILE_DEVICE_CD_ROM:
+ case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
+ DriveType = DOSDEVICE_DRIVE_CDROM;
+ break;
+ case FILE_DEVICE_DISK:
+ case FILE_DEVICE_DISK_FILE_SYSTEM:
+ case FILE_DEVICE_FILE_SYSTEM:
+ if (((PDEVICE_OBJECT)Object)->Characteristics & FILE_REMOVABLE_MEDIA)
+ DriveType = DOSDEVICE_DRIVE_REMOVABLE;
+ else
+ DriveType = DOSDEVICE_DRIVE_FIXED;
+ break;
+ case FILE_DEVICE_NETWORK:
+ case FILE_DEVICE_NETWORK_FILE_SYSTEM:
+ DriveType = DOSDEVICE_DRIVE_REMOTE;
+ break;
+ default:
+ DPRINT1("Device Type %lu for %wZ is not known or unhandled\n",
+ ((PDEVICE_OBJECT)Object)->DeviceType,
+ &SymbolicLink->LinkTarget);
+ DriveType = DOSDEVICE_DRIVE_UNKNOWN;
+ }
}
- else
+
+ /* Add a new drive entry */
+ if (DeviceMap != NULL)
{
- /* Neither directory or symlink, stop */
- break;
+ /* Acquire the device map lock */
+ KeAcquireGuardedMutex(&ObpDeviceMapLock);
+
+ DeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex - 1] =
+ (UCHAR)DriveType;
+ DeviceMap->DriveMap |=
+ 1 << (SymbolicLink->DosDeviceDriveIndex - 1);
+
+ /* Release the device map lock */
+ KeReleaseGuardedMutex(&ObpDeviceMapLock);
}
}
- /* Return a valid object, only if object type is IoDeviceObject */
- if (*Object &&
- OBJECT_TO_OBJECT_HEADER(*Object)->Type != IoDeviceObjectType)
- {
- *Object = NULL;
- }
- return STATUS_SUCCESS;
+ /* Cleanup */
+ ObpReleaseLookupContext(&LookupContext);
+}
+
+VOID
+NTAPI
+ObpDeleteSymbolicLinkName(IN POBJECT_SYMBOLIC_LINK SymbolicLink)
+{
+ /* Just call the helper */
+ ObpProcessDosDeviceSymbolicLink(SymbolicLink, TRUE);
}
VOID
NTAPI
ObpCreateSymbolicLinkName(IN POBJECT_SYMBOLIC_LINK SymbolicLink)
{
+ WCHAR UpperDrive;
POBJECT_HEADER ObjectHeader;
POBJECT_HEADER_NAME_INFO ObjectNameInfo;
- PVOID Object = NULL;
- POBJECT_DIRECTORY Directory;
- UNICODE_STRING TargetPath;
- NTSTATUS Status;
- ULONG DriveType = DOSDEVICE_DRIVE_CALCULATE;
- ULONG ReparseCnt;
- const ULONG MaxReparseAttempts = 20;
- OBP_LOOKUP_CONTEXT Context;
-
- /* FIXME: Need to support Device maps */
/* Get header data */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink);
ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
- /* Check if we are not actually in a directory with a device map */
- if (!(ObjectNameInfo) ||
- !(ObjectNameInfo->Directory) /*||
- !(ObjectNameInfo->Directory->DeviceMap)*/)
+ /* No name info, nothing to create */
+ if (ObjectNameInfo == NULL)
{
- ObpDereferenceNameInfo(ObjectNameInfo);
return;
}
- /* Check if it's a DOS drive letter, and set the drive index accordingly */
- if (ObjectNameInfo->Name.Length == 2 * sizeof(WCHAR) &&
- ObjectNameInfo->Name.Buffer[1] == L':' &&
- ( (ObjectNameInfo->Name.Buffer[0] >= L'A' &&
- ObjectNameInfo->Name.Buffer[0] <= L'Z') ||
- (ObjectNameInfo->Name.Buffer[0] >= L'a' &&
- ObjectNameInfo->Name.Buffer[0] <= L'z') ))
+ /* If we have a device map, look for creating a letter based drive */
+ if (ObjectNameInfo->Directory != NULL &&
+ ObjectNameInfo->Directory->DeviceMap != NULL)
{
- SymbolicLink->DosDeviceDriveIndex =
- RtlUpcaseUnicodeChar(ObjectNameInfo->Name.Buffer[0]) - L'A';
- /* The Drive index start from 1 */
- SymbolicLink->DosDeviceDriveIndex++;
-
- /* Initialize lookup context */
- ObpInitializeLookupContext(&Context);
-
- /* Start the search from the root */
- Directory = ObpRootDirectoryObject;
- TargetPath = SymbolicLink->LinkTarget;
-
- /*
- * Locate the IoDeviceObject if any this symbolic link points to.
- * To prevent endless reparsing, setting an upper limit on the
- * number of reparses.
- */
- Status = STATUS_REPARSE_OBJECT;
- ReparseCnt = 0;
- while (Status == STATUS_REPARSE_OBJECT &&
- ReparseCnt < MaxReparseAttempts)
+ /* Is it a drive letter based name? */
+ if (ObjectNameInfo->Name.Length == 2 * sizeof(WCHAR))
{
- Status =
- ObpParseSymbolicLinkToIoDeviceObject(ObjectNameInfo->Directory,
- &Directory,
- &TargetPath,
- &Context,
- &Object);
- if (Status == STATUS_REPARSE_OBJECT)
- ReparseCnt++;
- }
-
- /* Cleanup lookup context */
- ObpReleaseLookupContext(&Context);
-
- /* Error, or max resparse attemtps exceeded */
- if (! NT_SUCCESS(Status) || ReparseCnt >= MaxReparseAttempts)
- {
- /* Cleanup */
- ObpDereferenceNameInfo(ObjectNameInfo);
- return;
- }
-
- if (Object)
- {
- /* Calculate the drive type */
- switch(((PDEVICE_OBJECT)Object)->DeviceType)
+ if (ObjectNameInfo->Name.Buffer[1] == L':')
{
- case FILE_DEVICE_VIRTUAL_DISK:
- DriveType = DOSDEVICE_DRIVE_RAMDISK;
- break;
- case FILE_DEVICE_CD_ROM:
- case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
- DriveType = DOSDEVICE_DRIVE_CDROM;
- break;
- case FILE_DEVICE_DISK:
- case FILE_DEVICE_DISK_FILE_SYSTEM:
- case FILE_DEVICE_FILE_SYSTEM:
- if (((PDEVICE_OBJECT)Object)->Characteristics & FILE_REMOVABLE_MEDIA)
- DriveType = DOSDEVICE_DRIVE_REMOVABLE;
- else
- DriveType = DOSDEVICE_DRIVE_FIXED;
- break;
- case FILE_DEVICE_NETWORK:
- case FILE_DEVICE_NETWORK_FILE_SYSTEM:
- DriveType = DOSDEVICE_DRIVE_REMOTE;
- break;
- default:
- DPRINT1("Device Type %lu for %wZ is not known or unhandled\n",
- ((PDEVICE_OBJECT)Object)->DeviceType,
- &SymbolicLink->LinkTarget);
- DriveType = DOSDEVICE_DRIVE_UNKNOWN;
+ UpperDrive = RtlUpcaseUnicodeChar(ObjectNameInfo->Name.Buffer[0]);
+ if (UpperDrive >= L'A' && UpperDrive <= L'Z')
+ {
+ /* Compute its index (it's 1 based - 0 means no letter) */
+ SymbolicLink->DosDeviceDriveIndex = UpperDrive - (L'A' - 1);
+ }
}
}
- /* Add a new drive entry */
- KeAcquireGuardedMutex(&ObpDeviceMapLock);
- ObSystemDeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex-1] =
- (UCHAR)DriveType;
- ObSystemDeviceMap->DriveMap |=
- 1 << (SymbolicLink->DosDeviceDriveIndex-1);
- KeReleaseGuardedMutex(&ObpDeviceMapLock);
+ /* Call the helper */
+ ObpProcessDosDeviceSymbolicLink(SymbolicLink, FALSE);
}
- /* Cleanup */
+ /* We're done */
ObpDereferenceNameInfo(ObjectNameInfo);
}