2006-05-23 21:42:28 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Kernel
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
2008-08-16 17:53:28 +00:00
|
|
|
* FILE: ntoskrnl/ob/oblink.c
|
2006-05-23 21:42:28 +00:00
|
|
|
* PURPOSE: Implements symbolic links
|
|
|
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
|
|
|
* David Welch (welch@mcmail.com)
|
|
|
|
*/
|
2003-02-25 16:50:46 +00:00
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
2003-02-25 16:50:46 +00:00
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
2003-02-25 16:50:46 +00:00
|
|
|
|
2003-10-14 14:45:23 +00:00
|
|
|
/* GLOBALS ******************************************************************/
|
2003-02-25 16:50:46 +00:00
|
|
|
|
2018-02-13 20:33:04 +00:00
|
|
|
POBJECT_TYPE ObpSymbolicLinkObjectType = NULL;
|
2003-02-25 16:50:46 +00:00
|
|
|
|
2006-05-23 21:42:28 +00:00
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
|
2007-01-08 19:52:49 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
ObpDeleteSymbolicLinkName(IN POBJECT_SYMBOLIC_LINK SymbolicLink)
|
|
|
|
{
|
2011-04-25 16:08:00 +00:00
|
|
|
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 */
|
2007-01-08 19:52:49 +00:00
|
|
|
|
2011-04-25 16:08:00 +00:00
|
|
|
/* 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;
|
|
|
|
|
2018-02-13 20:33:04 +00:00
|
|
|
if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObpDirectoryObjectType)
|
2011-04-25 16:08:00 +00:00
|
|
|
{
|
|
|
|
/* Make this current directory, and continue search */
|
|
|
|
*Directory = (POBJECT_DIRECTORY)*Object;
|
|
|
|
}
|
2018-02-13 20:33:04 +00:00
|
|
|
else if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObpSymbolicLinkObjectType &&
|
2011-04-25 16:08:00 +00:00
|
|
|
(((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;
|
2007-01-08 19:52:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
ObpCreateSymbolicLinkName(IN POBJECT_SYMBOLIC_LINK SymbolicLink)
|
|
|
|
{
|
|
|
|
POBJECT_HEADER ObjectHeader;
|
|
|
|
POBJECT_HEADER_NAME_INFO ObjectNameInfo;
|
2011-04-25 16:08:00 +00:00
|
|
|
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 */
|
2007-01-08 19:52:49 +00:00
|
|
|
|
|
|
|
/* Get header data */
|
|
|
|
ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink);
|
2011-04-25 16:08:00 +00:00
|
|
|
ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
|
2007-01-08 19:52:49 +00:00
|
|
|
|
|
|
|
/* Check if we are not actually in a directory with a device map */
|
|
|
|
if (!(ObjectNameInfo) ||
|
2011-04-25 16:08:00 +00:00
|
|
|
!(ObjectNameInfo->Directory) /*||
|
|
|
|
!(ObjectNameInfo->Directory->DeviceMap)*/)
|
2007-01-08 19:52:49 +00:00
|
|
|
{
|
2011-04-25 16:08:00 +00:00
|
|
|
ObpDereferenceNameInfo(ObjectNameInfo);
|
2007-01-08 19:52:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-04-25 16:08:00 +00:00
|
|
|
/* 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:
|
2013-08-31 16:02:13 +00:00
|
|
|
DPRINT1("Device Type %lu for %wZ is not known or unhandled\n",
|
2011-04-25 16:08:00 +00:00
|
|
|
((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);
|
2007-01-08 19:52:49 +00:00
|
|
|
}
|
|
|
|
|
2006-05-23 21:42:28 +00:00
|
|
|
/*++
|
|
|
|
* @name ObpDeleteSymbolicLink
|
|
|
|
*
|
|
|
|
* The ObpDeleteSymbolicLink routine <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param ObjectBody
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @return None.
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
VOID
|
|
|
|
NTAPI
|
2003-02-25 16:50:46 +00:00
|
|
|
ObpDeleteSymbolicLink(PVOID ObjectBody)
|
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ObjectBody;
|
|
|
|
|
|
|
|
/* Make sure that the symbolic link has a name */
|
|
|
|
if (SymlinkObject->LinkTarget.Buffer)
|
|
|
|
{
|
|
|
|
/* Free the name */
|
|
|
|
ExFreePool(SymlinkObject->LinkTarget.Buffer);
|
|
|
|
SymlinkObject->LinkTarget.Buffer = NULL;
|
|
|
|
}
|
2003-02-25 16:50:46 +00:00
|
|
|
}
|
|
|
|
|
2006-05-23 21:42:28 +00:00
|
|
|
/*++
|
|
|
|
* @name ObpParseSymbolicLink
|
|
|
|
*
|
|
|
|
* The ObpParseSymbolicLink routine <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param Object
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param NextObject
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param FullPath
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param RemainingPath
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param Attributes
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @return STATUS_SUCCESS or appropriate error value.
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2006-05-25 01:18:31 +00:00
|
|
|
ObpParseSymbolicLink(IN PVOID ParsedObject,
|
|
|
|
IN PVOID ObjectType,
|
|
|
|
IN OUT PACCESS_STATE AccessState,
|
|
|
|
IN KPROCESSOR_MODE AccessMode,
|
|
|
|
IN ULONG Attributes,
|
|
|
|
IN OUT PUNICODE_STRING FullPath,
|
|
|
|
IN OUT PUNICODE_STRING RemainingName,
|
|
|
|
IN OUT PVOID Context OPTIONAL,
|
|
|
|
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
|
|
|
|
OUT PVOID *NextObject)
|
2003-02-25 16:50:46 +00:00
|
|
|
{
|
2006-05-25 01:18:31 +00:00
|
|
|
POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ParsedObject;
|
2006-05-24 02:45:06 +00:00
|
|
|
PUNICODE_STRING TargetPath;
|
|
|
|
PWSTR NewTargetPath;
|
2011-05-10 15:09:36 +00:00
|
|
|
ULONG LengthUsed, MaximumLength, TempLength;
|
2006-06-12 05:58:08 +00:00
|
|
|
NTSTATUS Status;
|
2009-09-02 13:02:30 +00:00
|
|
|
PAGED_CODE();
|
2006-06-12 05:58:08 +00:00
|
|
|
|
|
|
|
/* Assume failure */
|
|
|
|
*NextObject = NULL;
|
|
|
|
|
|
|
|
/* Check if we're out of name to parse */
|
|
|
|
if (!RemainingName->Length)
|
2003-02-25 16:50:46 +00:00
|
|
|
{
|
2006-06-12 05:58:08 +00:00
|
|
|
/* Check if we got an object type */
|
|
|
|
if (ObjectType)
|
|
|
|
{
|
|
|
|
/* Reference the object only */
|
|
|
|
Status = ObReferenceObjectByPointer(ParsedObject,
|
|
|
|
0,
|
|
|
|
ObjectType,
|
|
|
|
AccessMode);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Return it */
|
|
|
|
*NextObject = ParsedObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((NT_SUCCESS(Status)) || (Status != STATUS_OBJECT_TYPE_MISMATCH))
|
|
|
|
{
|
|
|
|
/* Fail */
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (RemainingName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)
|
|
|
|
{
|
|
|
|
/* Symbolic links must start with a backslash */
|
|
|
|
return STATUS_OBJECT_TYPE_MISMATCH;
|
2003-02-25 16:50:46 +00:00
|
|
|
}
|
|
|
|
|
2011-05-10 15:09:36 +00:00
|
|
|
/* Check if this symlink is bound to a specific object */
|
|
|
|
if (SymlinkObject->LinkTargetObject)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Set the target path and length */
|
|
|
|
TargetPath = &SymlinkObject->LinkTarget;
|
2011-05-10 15:09:36 +00:00
|
|
|
TempLength = TargetPath->Length;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Strip off the extra trailing '\', if we don't do this we will end up
|
|
|
|
* adding a extra '\' between TargetPath and RemainingName
|
|
|
|
* causing caller's like ObpLookupObjectName() to fail.
|
|
|
|
*/
|
|
|
|
if (TempLength && RemainingName->Length)
|
|
|
|
{
|
|
|
|
/* The target and remaining names aren't empty, so check for slashes */
|
|
|
|
if ((TargetPath->Buffer[TempLength / sizeof(WCHAR) - 1] ==
|
|
|
|
OBJ_NAME_PATH_SEPARATOR) &&
|
|
|
|
(RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
|
|
|
|
{
|
|
|
|
/* Reduce the length by one to cut off the extra '\' */
|
|
|
|
TempLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate the new length */
|
|
|
|
LengthUsed = TempLength + RemainingName->Length;
|
|
|
|
|
|
|
|
/* Check if it's not too much */
|
|
|
|
if (LengthUsed > 0xFFF0)
|
|
|
|
return STATUS_NAME_TOO_LONG;
|
2006-05-24 02:45:06 +00:00
|
|
|
|
|
|
|
/* Optimization: check if the new name is shorter */
|
|
|
|
if (FullPath->MaximumLength <= LengthUsed)
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* It's not, allocate a new one */
|
|
|
|
MaximumLength = LengthUsed + sizeof(WCHAR);
|
|
|
|
NewTargetPath = ExAllocatePoolWithTag(NonPagedPool,
|
|
|
|
MaximumLength,
|
2015-03-14 11:12:32 +00:00
|
|
|
OB_NAME_TAG);
|
2009-09-02 13:02:30 +00:00
|
|
|
if (!NewTargetPath) return STATUS_INSUFFICIENT_RESOURCES;
|
2006-05-24 02:45:06 +00:00
|
|
|
}
|
|
|
|
else
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* It is! Reuse the name... */
|
|
|
|
MaximumLength = FullPath->MaximumLength;
|
|
|
|
NewTargetPath = FullPath->Buffer;
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Make sure we have a length */
|
2006-06-12 05:58:08 +00:00
|
|
|
if (RemainingName->Length)
|
2006-05-24 02:45:06 +00:00
|
|
|
{
|
|
|
|
/* Copy the new path */
|
2011-05-10 15:09:36 +00:00
|
|
|
RtlMoveMemory((PVOID)((ULONG_PTR)NewTargetPath + TempLength),
|
2006-06-12 05:58:08 +00:00
|
|
|
RemainingName->Buffer,
|
|
|
|
RemainingName->Length);
|
2006-05-24 02:45:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the target path and null-terminate it */
|
2011-05-10 15:09:36 +00:00
|
|
|
RtlCopyMemory(NewTargetPath, TargetPath->Buffer, TempLength);
|
2006-05-24 02:45:06 +00:00
|
|
|
NewTargetPath[LengthUsed / sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
|
|
|
|
/* If the optimization didn't work, free the old buffer */
|
|
|
|
if (NewTargetPath != FullPath->Buffer) ExFreePool(FullPath->Buffer);
|
|
|
|
|
|
|
|
/* Update the path values */
|
2006-10-26 01:49:51 +00:00
|
|
|
FullPath->Length = (USHORT)LengthUsed;
|
|
|
|
FullPath->MaximumLength = (USHORT)MaximumLength;
|
2006-05-24 02:45:06 +00:00
|
|
|
FullPath->Buffer = NewTargetPath;
|
2003-02-25 16:50:46 +00:00
|
|
|
|
2006-06-12 05:58:08 +00:00
|
|
|
/* Tell the parse routine to start reparsing */
|
2006-05-23 21:42:28 +00:00
|
|
|
return STATUS_REPARSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
|
|
|
|
/*++
|
|
|
|
* @name NtCreateSymbolicLinkObject
|
|
|
|
* @implemented NT4
|
|
|
|
*
|
|
|
|
* The NtCreateSymbolicLinkObject opens or creates a symbolic link object.
|
|
|
|
*
|
|
|
|
* @param LinkHandle
|
|
|
|
* Variable which receives the symlink handle.
|
|
|
|
*
|
|
|
|
* @param DesiredAccess
|
|
|
|
* Desired access to the symlink.
|
|
|
|
*
|
|
|
|
* @param ObjectAttributes
|
|
|
|
* Structure describing the symlink.
|
|
|
|
*
|
|
|
|
* @param LinkTarget
|
|
|
|
* Unicode string defining the symlink's target
|
|
|
|
*
|
|
|
|
* @return STATUS_SUCCESS or appropriate error value.
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2004-10-24 20:37:27 +00:00
|
|
|
NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
|
2006-05-23 21:42:28 +00:00
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
|
|
IN PUNICODE_STRING LinkTarget)
|
2003-02-25 16:50:46 +00:00
|
|
|
{
|
2006-05-23 21:42:28 +00:00
|
|
|
HANDLE hLink;
|
2006-05-24 02:45:06 +00:00
|
|
|
POBJECT_SYMBOLIC_LINK SymbolicLink;
|
2006-05-23 21:42:28 +00:00
|
|
|
UNICODE_STRING CapturedLinkTarget;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
2009-08-26 17:31:02 +00:00
|
|
|
NTSTATUS Status;
|
2006-05-23 21:42:28 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Check if we need to probe parameters */
|
2009-08-26 17:31:02 +00:00
|
|
|
if (PreviousMode != KernelMode)
|
2005-02-22 21:09:54 +00:00
|
|
|
{
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Probe the target */
|
2006-05-24 14:41:53 +00:00
|
|
|
CapturedLinkTarget = ProbeForReadUnicodeString(LinkTarget);
|
2006-05-24 02:45:06 +00:00
|
|
|
ProbeForRead(CapturedLinkTarget.Buffer,
|
|
|
|
CapturedLinkTarget.MaximumLength,
|
|
|
|
sizeof(WCHAR));
|
|
|
|
|
|
|
|
/* Probe the return handle */
|
2006-05-23 21:42:28 +00:00
|
|
|
ProbeForWriteHandle(LinkHandle);
|
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2009-08-26 17:31:02 +00:00
|
|
|
/* Return the exception code */
|
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2006-05-24 02:45:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No need to capture */
|
|
|
|
CapturedLinkTarget = *LinkTarget;
|
2005-02-22 21:09:54 +00:00
|
|
|
}
|
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Check if the maximum length is odd */
|
|
|
|
if (CapturedLinkTarget.MaximumLength % sizeof(WCHAR))
|
2005-02-22 21:09:54 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Round it down */
|
|
|
|
CapturedLinkTarget.MaximumLength =
|
2006-10-26 01:49:51 +00:00
|
|
|
(USHORT)ALIGN_DOWN(CapturedLinkTarget.MaximumLength, WCHAR);
|
2005-02-22 21:09:54 +00:00
|
|
|
}
|
2006-05-23 21:42:28 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Fail if the length is odd, or if the maximum is smaller or 0 */
|
|
|
|
if ((CapturedLinkTarget.Length % sizeof(WCHAR)) ||
|
|
|
|
(CapturedLinkTarget.MaximumLength < CapturedLinkTarget.Length) ||
|
|
|
|
!(CapturedLinkTarget.MaximumLength))
|
|
|
|
{
|
|
|
|
/* This message is displayed on the debugger in Windows */
|
|
|
|
DbgPrint("OB: Invalid symbolic link target - %wZ\n",
|
|
|
|
&CapturedLinkTarget);
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the object */
|
2006-05-23 21:42:28 +00:00
|
|
|
Status = ObCreateObject(PreviousMode,
|
2018-02-13 20:33:04 +00:00
|
|
|
ObpSymbolicLinkObjectType,
|
2006-05-23 21:42:28 +00:00
|
|
|
ObjectAttributes,
|
|
|
|
PreviousMode,
|
|
|
|
NULL,
|
2006-05-24 02:45:06 +00:00
|
|
|
sizeof(OBJECT_SYMBOLIC_LINK),
|
2006-05-23 21:42:28 +00:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
(PVOID*)&SymbolicLink);
|
2005-02-22 21:09:54 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
2003-09-25 20:09:56 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Success! Fill in the creation time immediately */
|
|
|
|
KeQuerySystemTime(&SymbolicLink->CreationTime);
|
|
|
|
|
|
|
|
/* Setup the target name */
|
|
|
|
SymbolicLink->LinkTarget.Length = CapturedLinkTarget.Length;
|
2016-07-03 08:54:20 +00:00
|
|
|
SymbolicLink->LinkTarget.MaximumLength = CapturedLinkTarget.MaximumLength;
|
2007-10-19 23:21:45 +00:00
|
|
|
SymbolicLink->LinkTarget.Buffer =
|
2006-05-24 02:45:06 +00:00
|
|
|
ExAllocatePoolWithTag(PagedPool,
|
|
|
|
CapturedLinkTarget.MaximumLength,
|
2006-05-23 21:42:28 +00:00
|
|
|
TAG_SYMLINK_TARGET);
|
[NTOSKRNL]
Coverity code defects fixes :
- Cache: CID 701441
- Config: CIDs 716570, 716669, 716760
- Dbgk: Kdbg: CIDs 716571, 515128/9, 500432
- Ex: CIDs 500156/7, 515122, 716200/67, 701301, 514669
- Fsrtl: Fstub: CIDs 701341/2, 701288, 716770, 701302, and CIDs 716576/7/8 + 514636 + 716805 thanks to Thomas Faber
- Io: CIDs 514576, 514643, 514672/3, 716203, 716269, 716581, 716591, 716713
- Ke: CIDs 515125, 716592
- Ps: CIDs 716603/4, 701422
- Ob: Po: CIDs 514671/680, 701419/420/421, 716763, 716601/2
All the details are given in the different bug reports.
CORE-6677 CORE-6679 CORE-6680 CORE-6683 CORE-6686 CORE-6692 CORE-6693 CORE-6694 CORE-6695 CORE-6696 #comment Committed in rev.57400 #resolve #close
svn path=/trunk/; revision=57400
2012-09-27 17:16:31 +00:00
|
|
|
if (!SymbolicLink->LinkTarget.Buffer)
|
|
|
|
{
|
|
|
|
/* Dereference the symbolic link object and fail */
|
|
|
|
ObDereferenceObject(SymbolicLink);
|
|
|
|
return STATUS_NO_MEMORY;
|
|
|
|
}
|
2006-05-23 21:42:28 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Copy it */
|
2016-07-03 08:22:43 +00:00
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
RtlCopyMemory(SymbolicLink->LinkTarget.Buffer,
|
|
|
|
CapturedLinkTarget.Buffer,
|
|
|
|
CapturedLinkTarget.MaximumLength);
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
ObDereferenceObject(SymbolicLink);
|
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
2006-05-23 21:42:28 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Initialize the remaining name, dos drive index and target object */
|
|
|
|
SymbolicLink->LinkTargetObject = NULL;
|
|
|
|
SymbolicLink->DosDeviceDriveIndex = 0;
|
|
|
|
RtlInitUnicodeString(&SymbolicLink->LinkTargetRemaining, NULL);
|
2006-05-23 21:42:28 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Insert it into the object tree */
|
|
|
|
Status = ObInsertObject(SymbolicLink,
|
2006-05-23 21:42:28 +00:00
|
|
|
NULL,
|
|
|
|
DesiredAccess,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
&hLink);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Return the handle to caller */
|
2006-05-23 21:42:28 +00:00
|
|
|
*LinkHandle = hLink;
|
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Get exception code */
|
2008-11-24 13:40:26 +00:00
|
|
|
Status = _SEH2_GetExceptionCode();
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
2003-09-25 20:09:56 +00:00
|
|
|
}
|
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Return status to caller */
|
2006-05-23 21:42:28 +00:00
|
|
|
return Status;
|
2003-02-25 16:50:46 +00:00
|
|
|
}
|
|
|
|
|
2006-05-23 21:42:28 +00:00
|
|
|
/*++
|
|
|
|
* @name NtOpenSymbolicLinkObject
|
|
|
|
* @implemented NT4
|
|
|
|
*
|
|
|
|
* The NtOpenSymbolicLinkObject opens a symbolic link object.
|
|
|
|
*
|
|
|
|
* @param LinkHandle
|
|
|
|
* Variable which receives the symlink handle.
|
|
|
|
*
|
|
|
|
* @param DesiredAccess
|
|
|
|
* Desired access to the symlink.
|
|
|
|
*
|
|
|
|
* @param ObjectAttributes
|
|
|
|
* Structure describing the symlink.
|
|
|
|
*
|
|
|
|
* @return STATUS_SUCCESS or appropriate error value.
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2003-02-25 16:50:46 +00:00
|
|
|
NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
|
2006-05-23 21:42:28 +00:00
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
2003-02-25 16:50:46 +00:00
|
|
|
{
|
2006-05-23 21:42:28 +00:00
|
|
|
HANDLE hLink;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
2009-08-26 17:31:02 +00:00
|
|
|
NTSTATUS Status;
|
2006-05-23 21:42:28 +00:00
|
|
|
PAGED_CODE();
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Check if we need to probe parameters */
|
2009-08-26 17:31:02 +00:00
|
|
|
if (PreviousMode != KernelMode)
|
2005-02-22 21:09:54 +00:00
|
|
|
{
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Probe the return handle */
|
2006-05-23 21:42:28 +00:00
|
|
|
ProbeForWriteHandle(LinkHandle);
|
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2009-08-26 17:31:02 +00:00
|
|
|
/* Return the exception code */
|
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2005-02-22 21:09:54 +00:00
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Open the object */
|
2006-05-23 21:42:28 +00:00
|
|
|
Status = ObOpenObjectByName(ObjectAttributes,
|
2018-02-13 20:33:04 +00:00
|
|
|
ObpSymbolicLinkObjectType,
|
2006-05-23 21:42:28 +00:00
|
|
|
PreviousMode,
|
2006-05-25 20:50:58 +00:00
|
|
|
NULL,
|
2006-05-23 21:42:28 +00:00
|
|
|
DesiredAccess,
|
|
|
|
NULL,
|
|
|
|
&hLink);
|
2016-07-05 22:24:54 +00:00
|
|
|
|
|
|
|
_SEH2_TRY
|
2005-02-22 21:09:54 +00:00
|
|
|
{
|
2016-07-05 22:24:54 +00:00
|
|
|
/* Return the handle to caller */
|
|
|
|
*LinkHandle = hLink;
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
|
|
{
|
|
|
|
/* Get exception code */
|
|
|
|
Status = _SEH2_GetExceptionCode();
|
2005-02-22 21:09:54 +00:00
|
|
|
}
|
2016-07-05 22:24:54 +00:00
|
|
|
_SEH2_END;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Return status to caller */
|
2006-05-23 21:42:28 +00:00
|
|
|
return Status;
|
2003-02-25 16:50:46 +00:00
|
|
|
}
|
|
|
|
|
2006-05-23 21:42:28 +00:00
|
|
|
/*++
|
|
|
|
* @name NtQuerySymbolicLinkObject
|
|
|
|
* @implemented NT4
|
|
|
|
*
|
|
|
|
* The NtQuerySymbolicLinkObject queries a symbolic link object.
|
|
|
|
*
|
|
|
|
* @param LinkHandle
|
|
|
|
* Symlink handle to query
|
|
|
|
*
|
|
|
|
* @param LinkTarget
|
|
|
|
* Unicode string defining the symlink's target
|
|
|
|
*
|
|
|
|
* @param ResultLength
|
|
|
|
* Caller supplied storage for the number of bytes written (or NULL).
|
|
|
|
*
|
|
|
|
* @return STATUS_SUCCESS or appropriate error value.
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2003-02-25 16:50:46 +00:00
|
|
|
NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
|
2006-05-23 21:42:28 +00:00
|
|
|
OUT PUNICODE_STRING LinkTarget,
|
|
|
|
OUT PULONG ResultLength OPTIONAL)
|
2003-02-25 16:50:46 +00:00
|
|
|
{
|
2008-12-03 17:28:59 +00:00
|
|
|
UNICODE_STRING SafeLinkTarget = { 0, 0, NULL };
|
2006-05-24 02:45:06 +00:00
|
|
|
POBJECT_SYMBOLIC_LINK SymlinkObject;
|
2006-05-23 21:42:28 +00:00
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
2009-08-26 17:31:02 +00:00
|
|
|
NTSTATUS Status;
|
2006-05-24 02:45:06 +00:00
|
|
|
ULONG LengthUsed;
|
2006-05-23 21:42:28 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
2009-08-26 17:31:02 +00:00
|
|
|
if (PreviousMode != KernelMode)
|
2005-02-22 21:09:54 +00:00
|
|
|
{
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Probe the unicode string for read and write */
|
2006-05-24 14:41:53 +00:00
|
|
|
ProbeForWriteUnicodeString(LinkTarget);
|
2006-05-23 21:42:28 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Probe the unicode string's buffer for write */
|
2006-05-23 21:42:28 +00:00
|
|
|
SafeLinkTarget = *LinkTarget;
|
|
|
|
ProbeForWrite(SafeLinkTarget.Buffer,
|
|
|
|
SafeLinkTarget.MaximumLength,
|
2006-05-24 14:41:53 +00:00
|
|
|
sizeof(WCHAR));
|
2006-05-23 21:42:28 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Probe the return length */
|
2009-08-26 17:31:02 +00:00
|
|
|
if (ResultLength) ProbeForWriteUlong(ResultLength);
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2009-08-26 17:31:02 +00:00
|
|
|
/* Return the exception code */
|
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2005-02-22 21:09:54 +00:00
|
|
|
}
|
2006-05-23 21:42:28 +00:00
|
|
|
else
|
2005-02-22 21:09:54 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* No need to probe */
|
2006-05-23 21:42:28 +00:00
|
|
|
SafeLinkTarget = *LinkTarget;
|
2005-02-22 21:09:54 +00:00
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Reference the object */
|
2006-05-23 21:42:28 +00:00
|
|
|
Status = ObReferenceObjectByHandle(LinkHandle,
|
|
|
|
SYMBOLIC_LINK_QUERY,
|
2018-02-13 20:33:04 +00:00
|
|
|
ObpSymbolicLinkObjectType,
|
2006-05-23 21:42:28 +00:00
|
|
|
PreviousMode,
|
|
|
|
(PVOID *)&SymlinkObject,
|
|
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(Status))
|
2003-09-03 15:12:16 +00:00
|
|
|
{
|
2008-04-01 20:07:36 +00:00
|
|
|
/* Lock the object */
|
|
|
|
ObpAcquireObjectLock(OBJECT_TO_OBJECT_HEADER(SymlinkObject));
|
2006-05-24 02:45:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* So here's the thing: If you specify a return length, then the
|
|
|
|
* implementation will use the maximum length. If you don't, then
|
|
|
|
* it will use the length.
|
|
|
|
*/
|
|
|
|
LengthUsed = ResultLength ? SymlinkObject->LinkTarget.MaximumLength :
|
|
|
|
SymlinkObject->LinkTarget.Length;
|
|
|
|
|
|
|
|
/* Enter SEH so we can safely copy */
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Make sure our buffer will fit */
|
|
|
|
if (LengthUsed <= SafeLinkTarget.MaximumLength)
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Copy the buffer */
|
2006-05-24 14:41:53 +00:00
|
|
|
RtlCopyMemory(SafeLinkTarget.Buffer,
|
2006-05-24 02:45:06 +00:00
|
|
|
SymlinkObject->LinkTarget.Buffer,
|
|
|
|
LengthUsed);
|
|
|
|
|
|
|
|
/* Copy the new length */
|
|
|
|
LinkTarget->Length = SymlinkObject->LinkTarget.Length;
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Otherwise set the failure status */
|
2006-05-23 21:42:28 +00:00
|
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* In both cases, check if the required length was requested */
|
|
|
|
if (ResultLength)
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Then return it */
|
|
|
|
*ResultLength = SymlinkObject->LinkTarget.MaximumLength;
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
2006-05-23 21:42:28 +00:00
|
|
|
{
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Get the error code */
|
2008-11-24 13:40:26 +00:00
|
|
|
Status = _SEH2_GetExceptionCode();
|
2006-05-23 21:42:28 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2006-05-23 21:42:28 +00:00
|
|
|
|
2008-05-14 20:59:43 +00:00
|
|
|
/* Unlock and dereference the object */
|
2008-04-01 20:07:36 +00:00
|
|
|
ObpReleaseObjectLock(OBJECT_TO_OBJECT_HEADER(SymlinkObject));
|
2006-05-23 21:42:28 +00:00
|
|
|
ObDereferenceObject(SymlinkObject);
|
2003-09-03 15:12:16 +00:00
|
|
|
}
|
2003-02-25 16:50:46 +00:00
|
|
|
|
2006-05-24 02:45:06 +00:00
|
|
|
/* Return query status */
|
2006-05-23 21:42:28 +00:00
|
|
|
return Status;
|
2003-02-25 16:50:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|