X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=ntoskrnl%2Fob%2Foblink.c;h=3648aa797a50a91a1b5058b8f47bb889ee6de541;hp=5b147474c0c7d0a6f8af0dce6df22b1b32bccb5f;hb=b726d7355f0aa394852fa8c56e59cfc9bbc4293c;hpb=9ab4e6808d239977bcba0066e3ca3a64bec5d64b diff --git a/ntoskrnl/ob/oblink.c b/ntoskrnl/ob/oblink.c index 5b147474c0c..3648aa797a5 100644 --- a/ntoskrnl/ob/oblink.c +++ b/ntoskrnl/ob/oblink.c @@ -23,8 +23,160 @@ VOID NTAPI ObpDeleteSymbolicLinkName(IN POBJECT_SYMBOLIC_LINK SymbolicLink) { - /* FIXME: Device maps not supported yet */ + POBJECT_HEADER ObjectHeader; + POBJECT_HEADER_NAME_INFO ObjectNameInfo; + + /* 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)*/) + { + ObpDereferenceNameInfo(ObjectNameInfo); + return; + } + + /* 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') )) + { + /* 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; + } + + 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; + + if (! TargetPath || ! Object || ! Context || ! Directory || + ! SymbolicLinkDirectory) + { + return STATUS_INVALID_PARAMETER; + } + + /* FIXME: Need to support Device maps */ + + /* 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) + { + TargetPath->Buffer++; + TargetPath->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); + } + + /* Remember the current component of the target path */ + Name = *TargetPath; + + /* Move forward to the next component of the target path */ + while (TargetPath->Length >= sizeof(OBJ_NAME_PATH_SEPARATOR)) + { + if (TargetPath->Buffer[0] != OBJ_NAME_PATH_SEPARATOR) + { + TargetPath->Buffer++; + TargetPath->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); + } + else + break; + } + + Name.Length -= TargetPath->Length; + + /* Finished processing the entire path, stop */ + if (! Name.Length) + break; + /* + * 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) + { + /* Fake lock state so that ObpLookupEntryDirectory() doesn't attempt a lock */ + ManualUnlock = TRUE; + Context->DirectoryLocked = TRUE; + } + else + ManualUnlock = FALSE; + + *Object = ObpLookupEntryDirectory(*Directory, + &Name, + 0, + FALSE, + Context); + + /* Locking was faked, undo it now */ + if (*Directory == SymbolicLinkDirectory && ManualUnlock) + Context->DirectoryLocked = FALSE; + + /* Lookup failed, stop */ + if (! *Object) + break; + + if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObDirectoryType) + { + /* Make this current directory, and continue search */ + *Directory = (POBJECT_DIRECTORY)*Object; + } + else if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObSymbolicLinkType && + (((POBJECT_SYMBOLIC_LINK)*Object)->DosDeviceDriveIndex == 0)) + { + /* Symlink points to another initialized symlink, ask caller to reparse */ + *Directory = ObpRootDirectoryObject; + TargetPath = &((POBJECT_SYMBOLIC_LINK)*Object)->LinkTarget; + return STATUS_REPARSE_OBJECT; + } + else + { + /* Neither directory or symlink, stop */ + break; + } + } + + /* Return a valid object, only if object type is IoDeviceObject */ + if (*Object && + OBJECT_TO_OBJECT_HEADER(*Object)->Type != IoDeviceObjectType) + { + *Object = NULL; + } + return STATUS_SUCCESS; } VOID @@ -33,23 +185,124 @@ ObpCreateSymbolicLinkName(IN POBJECT_SYMBOLIC_LINK SymbolicLink) { 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 = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); + ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader); /* Check if we are not actually in a directory with a device map */ if (!(ObjectNameInfo) || - !(ObjectNameInfo->Directory) || - !(ObjectNameInfo->Directory->DeviceMap)) + !(ObjectNameInfo->Directory) /*|| + !(ObjectNameInfo->Directory->DeviceMap)*/) { - /* There's nothing to do, return */ + ObpDereferenceNameInfo(ObjectNameInfo); return; } - /* FIXME: We don't support device maps yet */ - DPRINT1("Unhandled path!\n"); - ASSERT(FALSE); + /* 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') )) + { + 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) + { + 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) + { + 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 %ld for %wZ is not known or unhandled\n", + ((PDEVICE_OBJECT)Object)->DeviceType, + &SymbolicLink->LinkTarget); + DriveType = DOSDEVICE_DRIVE_UNKNOWN; + } + } + + /* Add a new drive entry */ + KeAcquireGuardedMutex(&ObpDeviceMapLock); + ObSystemDeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex-1] = + (UCHAR)DriveType; + ObSystemDeviceMap->DriveMap |= + 1 << (SymbolicLink->DosDeviceDriveIndex-1); + KeReleaseGuardedMutex(&ObpDeviceMapLock); + } + + /* Cleanup */ + ObpDereferenceNameInfo(ObjectNameInfo); } /*++