mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 05:42:59 +00:00
453 lines
10 KiB
C
453 lines
10 KiB
C
/* $Id: symlink.c,v 1.27 2002/06/20 21:30:33 ekohl Exp $
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: ntoskrnl/io/symlink.c
|
|
* PURPOSE: Implements symbolic links
|
|
* PROGRAMMER: David Welch (welch@mcmail.com)
|
|
* UPDATE HISTORY:
|
|
* Created 22/05/98
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <limits.h>
|
|
#include <ddk/ntddk.h>
|
|
#include <internal/pool.h>
|
|
|
|
#define NDEBUG
|
|
#include <internal/debug.h>
|
|
|
|
/* GLOBALS ******************************************************************/
|
|
|
|
typedef struct
|
|
{
|
|
CSHORT Type;
|
|
CSHORT Size;
|
|
UNICODE_STRING TargetName;
|
|
OBJECT_ATTRIBUTES Target;
|
|
} SYMLNK_OBJECT, *PSYMLNK_OBJECT;
|
|
|
|
POBJECT_TYPE IoSymbolicLinkType = NULL;
|
|
|
|
static GENERIC_MAPPING IopSymbolicLinkMapping = {
|
|
STANDARD_RIGHTS_READ|SYMBOLIC_LINK_QUERY,
|
|
STANDARD_RIGHTS_WRITE,
|
|
STANDARD_RIGHTS_EXECUTE|SYMBOLIC_LINK_QUERY,
|
|
SYMBOLIC_LINK_ALL_ACCESS};
|
|
|
|
#define TAG_SYMLINK_TTARGET TAG('S', 'Y', 'T', 'T')
|
|
#define TAG_SYMLINK_TARGET TAG('S', 'Y', 'M', 'T')
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
|
/**********************************************************************
|
|
* NAME INTERNAL
|
|
* IopCreateSymbolicLink
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* ARGUMENTS
|
|
*
|
|
* RETURNN VALUE
|
|
* Status.
|
|
*
|
|
* REVISIONS
|
|
*/
|
|
NTSTATUS STDCALL
|
|
IopCreateSymbolicLink(PVOID Object,
|
|
PVOID Parent,
|
|
PWSTR RemainingPath,
|
|
POBJECT_ATTRIBUTES ObjectAttributes)
|
|
{
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* NAME INTERNAL
|
|
* IopParseSymbolicLink
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* ARGUMENTS
|
|
*
|
|
* RETURN VALUE
|
|
*
|
|
* REVISIONS
|
|
*/
|
|
NTSTATUS STDCALL
|
|
IopParseSymbolicLink(PVOID Object,
|
|
PVOID * NextObject,
|
|
PUNICODE_STRING FullPath,
|
|
PWSTR * RemainingPath,
|
|
ULONG Attributes)
|
|
{
|
|
PSYMLNK_OBJECT SymlinkObject = (PSYMLNK_OBJECT) Object;
|
|
UNICODE_STRING TargetPath;
|
|
|
|
DPRINT("IopParseSymbolicLink (RemainingPath %S)\n", *RemainingPath);
|
|
/*
|
|
* Stop parsing if the entire path has been parsed and
|
|
* the desired object is a symbolic link object.
|
|
*/
|
|
if (((*RemainingPath == NULL) || (**RemainingPath == 0)) &&
|
|
(Attributes & OBJ_OPENLINK))
|
|
{
|
|
DPRINT("Parsing stopped!\n");
|
|
*NextObject = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* build the expanded path */
|
|
TargetPath.MaximumLength = SymlinkObject->TargetName.Length + sizeof(WCHAR);
|
|
if (RemainingPath && *RemainingPath)
|
|
{
|
|
TargetPath.MaximumLength += (wcslen(*RemainingPath) * sizeof(WCHAR));
|
|
}
|
|
TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
|
|
TargetPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
|
|
TargetPath.MaximumLength,
|
|
TAG_SYMLINK_TTARGET);
|
|
wcscpy(TargetPath.Buffer, SymlinkObject->TargetName.Buffer);
|
|
if (RemainingPath && *RemainingPath)
|
|
{
|
|
wcscat(TargetPath.Buffer, *RemainingPath);
|
|
}
|
|
|
|
/* transfer target path buffer into FullPath */
|
|
RtlFreeUnicodeString(FullPath);
|
|
FullPath->Length = TargetPath.Length;
|
|
FullPath->MaximumLength = TargetPath.MaximumLength;
|
|
FullPath->Buffer = TargetPath.Buffer;
|
|
|
|
/* reinitialize RemainingPath for reparsing */
|
|
*RemainingPath = FullPath->Buffer;
|
|
|
|
*NextObject = NULL;
|
|
return STATUS_REPARSE;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* NAME INTERNAL
|
|
* IoInitSymbolicLinkImplementation
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* ARGUMENTS
|
|
* None.
|
|
*
|
|
* RETURNN VALUE
|
|
* None.
|
|
*
|
|
* REVISIONS
|
|
*/
|
|
VOID IoInitSymbolicLinkImplementation (VOID)
|
|
{
|
|
IoSymbolicLinkType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
|
|
|
|
IoSymbolicLinkType->Tag = TAG('S', 'Y', 'M', 'T');
|
|
IoSymbolicLinkType->TotalObjects = 0;
|
|
IoSymbolicLinkType->TotalHandles = 0;
|
|
IoSymbolicLinkType->MaxObjects = ULONG_MAX;
|
|
IoSymbolicLinkType->MaxHandles = ULONG_MAX;
|
|
IoSymbolicLinkType->PagedPoolCharge = 0;
|
|
IoSymbolicLinkType->NonpagedPoolCharge = sizeof (SYMLNK_OBJECT);
|
|
IoSymbolicLinkType->Mapping = &IopSymbolicLinkMapping;
|
|
IoSymbolicLinkType->Dump = NULL;
|
|
IoSymbolicLinkType->Open = NULL;
|
|
IoSymbolicLinkType->Close = NULL;
|
|
IoSymbolicLinkType->Delete = NULL;
|
|
IoSymbolicLinkType->Parse = IopParseSymbolicLink;
|
|
IoSymbolicLinkType->Security = NULL;
|
|
IoSymbolicLinkType->QueryName = NULL;
|
|
IoSymbolicLinkType->OkayToClose = NULL;
|
|
IoSymbolicLinkType->Create = IopCreateSymbolicLink;
|
|
IoSymbolicLinkType->DuplicationNotify = NULL;
|
|
|
|
RtlInitUnicodeString(&IoSymbolicLinkType->TypeName,
|
|
L"SymbolicLink");
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* NAME EXPORTED
|
|
* NtOpenSymbolicLinkObject
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* ARGUMENTS
|
|
*
|
|
* RETURN VALUE
|
|
*
|
|
* REVISIONS
|
|
*
|
|
*/
|
|
NTSTATUS STDCALL
|
|
NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
|
{
|
|
DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
|
|
ObjectAttributes->ObjectName);
|
|
|
|
return(ObOpenObjectByName(ObjectAttributes,
|
|
IoSymbolicLinkType,
|
|
NULL,
|
|
UserMode,
|
|
DesiredAccess,
|
|
NULL,
|
|
LinkHandle));
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* NAME EXPORTED
|
|
* NtQuerySymbolicLinkObject
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* ARGUMENTS
|
|
*
|
|
* RETURN VALUE
|
|
*
|
|
* REVISIONS
|
|
*
|
|
*/
|
|
NTSTATUS STDCALL
|
|
NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
|
|
IN OUT PUNICODE_STRING LinkTarget,
|
|
OUT PULONG ReturnedLength OPTIONAL)
|
|
{
|
|
PSYMLNK_OBJECT SymlinkObject;
|
|
NTSTATUS Status;
|
|
|
|
Status = ObReferenceObjectByHandle(LinkHandle,
|
|
SYMBOLIC_LINK_QUERY,
|
|
IoSymbolicLinkType,
|
|
UserMode,
|
|
(PVOID *)&SymlinkObject,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
RtlCopyUnicodeString(LinkTarget,
|
|
SymlinkObject->Target.ObjectName);
|
|
if (ReturnedLength != NULL)
|
|
{
|
|
*ReturnedLength = SymlinkObject->Target.Length;
|
|
}
|
|
ObDereferenceObject(SymlinkObject);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* NAME EXPORTED
|
|
* IoCreateUnprotectedSymbolicLink
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* ARGUMENTS
|
|
*
|
|
* RETURN VALUE
|
|
*
|
|
* REVISIONS
|
|
*
|
|
*/
|
|
NTSTATUS STDCALL
|
|
IoCreateUnprotectedSymbolicLink(PUNICODE_STRING SymbolicLinkName,
|
|
PUNICODE_STRING DeviceName)
|
|
{
|
|
return(IoCreateSymbolicLink(SymbolicLinkName,
|
|
DeviceName));
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* NAME EXPORTED
|
|
* IoCreateSymbolicLink
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* ARGUMENTS
|
|
*
|
|
* RETURN VALUE
|
|
*
|
|
* REVISIONS
|
|
*
|
|
*/
|
|
NTSTATUS STDCALL
|
|
IoCreateSymbolicLink(PUNICODE_STRING SymbolicLinkName,
|
|
PUNICODE_STRING DeviceName)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PSYMLNK_OBJECT SymbolicLink;
|
|
NTSTATUS Status;
|
|
|
|
assert_irql(PASSIVE_LEVEL);
|
|
|
|
DPRINT(
|
|
"IoCreateSymbolicLink(SymbolicLinkName %S, DeviceName %S)\n",
|
|
SymbolicLinkName->Buffer,
|
|
DeviceName->Buffer
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
& ObjectAttributes,
|
|
SymbolicLinkName,
|
|
OBJ_PERMANENT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status = ObCreateObject(
|
|
NULL,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
& ObjectAttributes,
|
|
IoSymbolicLinkType,
|
|
(PVOID*)&SymbolicLink
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(Status);
|
|
}
|
|
SymbolicLink->TargetName.Length = 0;
|
|
SymbolicLink->TargetName.MaximumLength =
|
|
((wcslen(DeviceName->Buffer) + 1) * sizeof(WCHAR));
|
|
SymbolicLink->TargetName.Buffer =
|
|
ExAllocatePoolWithTag(NonPagedPool,
|
|
SymbolicLink->TargetName.MaximumLength,
|
|
TAG_SYMLINK_TARGET);
|
|
RtlCopyUnicodeString(
|
|
& (SymbolicLink->TargetName),
|
|
DeviceName
|
|
);
|
|
|
|
DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
|
|
|
|
InitializeObjectAttributes(
|
|
& (SymbolicLink->Target),
|
|
& (SymbolicLink->TargetName),
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
DPRINT("%s() = STATUS_SUCCESS\n",__FUNCTION__);
|
|
ObDereferenceObject( SymbolicLink );
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* NAME EXPORTED
|
|
* IoDeleteSymbolicLink
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* ARGUMENTS
|
|
*
|
|
* RETURN VALUE
|
|
*
|
|
* REVISIONS
|
|
*
|
|
*/
|
|
NTSTATUS STDCALL
|
|
IoDeleteSymbolicLink(PUNICODE_STRING SymbolicLinkName)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Handle;
|
|
NTSTATUS Status;
|
|
|
|
assert_irql(PASSIVE_LEVEL);
|
|
|
|
DPRINT("IoDeleteSymbolicLink (SymbolicLinkName %S)\n",
|
|
SymbolicLinkName->Buffer);
|
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
SymbolicLinkName,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenSymbolicLinkObject (&Handle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
Status = NtMakeTemporaryObject (Handle);
|
|
NtClose (Handle);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* NAME (EXPORTED as Zw)
|
|
* NtCreateSymbolicLinkObject
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* ARGUMENTS
|
|
*
|
|
* RETURN VALUE
|
|
*
|
|
* REVISIONS
|
|
*
|
|
*/
|
|
NTSTATUS STDCALL
|
|
NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN PUNICODE_STRING DeviceName)
|
|
{
|
|
PSYMLNK_OBJECT SymbolicLink;
|
|
NTSTATUS Status;
|
|
|
|
assert_irql(PASSIVE_LEVEL);
|
|
|
|
DPRINT("NtCreateSymbolicLinkObject(SymbolicLinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, DeviceName %S)\n",
|
|
SymbolicLinkHandle,
|
|
DesiredAccess,
|
|
ObjectAttributes,
|
|
DeviceName->Buffer);
|
|
|
|
Status = ObCreateObject(SymbolicLinkHandle,
|
|
DesiredAccess,
|
|
ObjectAttributes,
|
|
IoSymbolicLinkType,
|
|
(PVOID*)&SymbolicLink);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
SymbolicLink->TargetName.Length = 0;
|
|
SymbolicLink->TargetName.MaximumLength =
|
|
((wcslen(DeviceName->Buffer) + 1) * sizeof(WCHAR));
|
|
SymbolicLink->TargetName.Buffer =
|
|
ExAllocatePoolWithTag(NonPagedPool,
|
|
SymbolicLink->TargetName.MaximumLength,
|
|
TAG_SYMLINK_TARGET);
|
|
RtlCopyUnicodeString(&SymbolicLink->TargetName,
|
|
DeviceName);
|
|
|
|
DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
|
|
|
|
InitializeObjectAttributes(&SymbolicLink->Target,
|
|
&SymbolicLink->TargetName,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
DPRINT("%s() = STATUS_SUCCESS\n",__FUNCTION__);
|
|
ObDereferenceObject(SymbolicLink);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
/* EOF */
|