+++ /dev/null
-/*
- * ReactOS kernel
- * Copyright (C) 2011-2012 ReactOS Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: drivers/filesystem/mountmgr/symlink.c
- * PURPOSE: Mount Manager - Symbolic links functions
- * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
- */
-
-#include "mntmgr.h"
-
-#define NDEBUG
-#include <debug.h>
-
-UNICODE_STRING DeviceMount = RTL_CONSTANT_STRING(MOUNTMGR_DEVICE_NAME);
-UNICODE_STRING DosDevicesMount = RTL_CONSTANT_STRING(L"\\DosDevices\\MountPointManager");
-UNICODE_STRING DosDevices = RTL_CONSTANT_STRING(L"\\DosDevices\\");
-UNICODE_STRING DeviceFloppy = RTL_CONSTANT_STRING(L"\\Device\\Floppy");
-UNICODE_STRING DeviceCdRom = RTL_CONSTANT_STRING(L"\\Device\\CdRom");
-UNICODE_STRING DosGlobal = RTL_CONSTANT_STRING(L"\\GLOBAL??\\");
-UNICODE_STRING Global = RTL_CONSTANT_STRING(L"\\??\\");
-UNICODE_STRING SafeVolumes = RTL_CONSTANT_STRING(L"\\Device\\VolumesSafeForWriteAccess");
-UNICODE_STRING Volume = RTL_CONSTANT_STRING(L"\\??\\Volume");
-UNICODE_STRING ReparseIndex = RTL_CONSTANT_STRING(L"\\$Extend\\$Reparse:$R:$INDEX_ALLOCATION");
-
-/*
- * @implemented
- */
-NTSTATUS
-CreateStringWithGlobal(IN PUNICODE_STRING DosName,
- OUT PUNICODE_STRING GlobalString)
-{
- UNICODE_STRING IntGlobal;
-
- if (RtlPrefixUnicodeString(&DosDevices, DosName, TRUE))
- {
- /* DOS device - use DOS global */
- IntGlobal.Length = DosName->Length - DosDevices.Length + DosGlobal.Length;
- IntGlobal.MaximumLength = IntGlobal.Length + sizeof(WCHAR);
- IntGlobal.Buffer = AllocatePool(IntGlobal.MaximumLength);
- if (!IntGlobal.Buffer)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- RtlCopyMemory(IntGlobal.Buffer, DosGlobal.Buffer, DosGlobal.Length);
- RtlCopyMemory(IntGlobal.Buffer + (DosGlobal.Length / sizeof(WCHAR)),
- DosName->Buffer + (DosDevices.Length / sizeof(WCHAR)),
- DosName->Length - DosDevices.Length);
- IntGlobal.Buffer[IntGlobal.Length / sizeof(WCHAR)] = UNICODE_NULL;
- }
- else if (RtlPrefixUnicodeString(&Global, DosName, TRUE))
- {
- /* Switch to DOS global */
- IntGlobal.Length = DosName->Length - Global.Length + DosGlobal.Length;
- IntGlobal.MaximumLength = IntGlobal.Length + sizeof(WCHAR);
- IntGlobal.Buffer = AllocatePool(IntGlobal.MaximumLength);
- if (!IntGlobal.Buffer)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- RtlCopyMemory(IntGlobal.Buffer, DosGlobal.Buffer, DosGlobal.Length);
- RtlCopyMemory(IntGlobal.Buffer + (DosGlobal.Length / sizeof(WCHAR)),
- DosName->Buffer + (Global.Length / sizeof(WCHAR)),
- DosName->Length - Global.Length);
- IntGlobal.Buffer[IntGlobal.Length / sizeof(WCHAR)] = UNICODE_NULL;
- }
- else
- {
- /* Simply duplicate string */
- IntGlobal.Length = DosName->Length;
- IntGlobal.MaximumLength = DosName->MaximumLength;
- IntGlobal.Buffer = AllocatePool(IntGlobal.MaximumLength);
- if (!IntGlobal.Buffer)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- RtlCopyMemory(IntGlobal.Buffer, DosName->Buffer, IntGlobal.MaximumLength);
- }
-
- /* Return string */
- GlobalString->Length = IntGlobal.Length;
- GlobalString->MaximumLength = IntGlobal.MaximumLength;
- GlobalString->Buffer = IntGlobal.Buffer;
-
- return STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-GlobalCreateSymbolicLink(IN PUNICODE_STRING DosName,
- IN PUNICODE_STRING DeviceName)
-{
- NTSTATUS Status;
- UNICODE_STRING GlobalName;
-
- UNREFERENCED_PARAMETER(DeviceName);
-
- /* First create the global string */
- Status = CreateStringWithGlobal(DosName, &GlobalName);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- /* Then, create the symlink */
- Status = IoCreateSymbolicLink(&GlobalName, DosName);
-
- FreePool(GlobalName.Buffer);
-
- return Status;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-GlobalDeleteSymbolicLink(IN PUNICODE_STRING DosName)
-{
- NTSTATUS Status;
- UNICODE_STRING GlobalName;
-
- /* Recreate the string (to find the link) */
- Status = CreateStringWithGlobal(DosName, &GlobalName);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- /* And delete the link */
- Status = IoDeleteSymbolicLink(&GlobalName);
-
- FreePool(GlobalName.Buffer);
-
- return Status;
-}
-
-/*
- * @implemented
- */
-VOID
-SendLinkCreated(IN PUNICODE_STRING SymbolicName)
-{
- PIRP Irp;
- KEVENT Event;
- ULONG NameSize;
- NTSTATUS Status;
- PFILE_OBJECT FileObject;
- PIO_STACK_LOCATION Stack;
- PMOUNTDEV_NAME Name = NULL;
- PDEVICE_OBJECT DeviceObject;
- IO_STATUS_BLOCK IoStatusBlock;
-
- /* Get the device associated with the name */
- Status = IoGetDeviceObjectPointer(SymbolicName,
- FILE_READ_ATTRIBUTES,
- &FileObject,
- &DeviceObject);
- if (!NT_SUCCESS(Status))
- {
- return;
- }
-
- /* Get attached device (will notify it) */
- DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
-
- /* NameSize is the size of the whole MOUNTDEV_NAME struct */
- NameSize = sizeof(USHORT) + SymbolicName->Length;
- Name = AllocatePool(NameSize);
- if (!Name)
- {
- goto Cleanup;
- }
-
- /* Initialize struct */
- Name->NameLength = SymbolicName->Length;
- RtlCopyMemory(Name->Name, SymbolicName->Buffer, SymbolicName->Length);
-
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- /* Microsoft does it twice... Once with limited access, second with any
- * So, first one here
- */
- Irp = IoBuildDeviceIoControlRequest(CTL_CODE(MOUNTDEVCONTROLTYPE, 4, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
- DeviceObject,
- Name,
- NameSize,
- NULL,
- 0,
- FALSE,
- &Event,
- &IoStatusBlock);
- /* This one can fail, no one matters */
- if (Irp)
- {
- Stack = IoGetNextIrpStackLocation(Irp);
- Stack->FileObject = FileObject;
-
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
- {
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
- }
- }
-
- /* Then, second one */
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_LINK_CREATED,
- DeviceObject,
- Name,
- NameSize,
- NULL,
- 0,
- FALSE,
- &Event,
- &IoStatusBlock);
- if (!Irp)
- {
- goto Cleanup;
- }
-
- Stack = IoGetNextIrpStackLocation(Irp);
- Stack->FileObject = FileObject;
-
- /* Really notify */
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
- {
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
- }
-
-Cleanup:
- if (Name)
- {
- FreePool(Name);
- }
-
- ObDereferenceObject(DeviceObject);
- ObDereferenceObject(FileObject);
-
- return;
-}
-
-/*
- * @implemented
- */
-VOID
-SendLinkDeleted(IN PUNICODE_STRING DeviceName,
- IN PUNICODE_STRING SymbolicName)
-{
- PIRP Irp;
- KEVENT Event;
- ULONG NameSize;
- NTSTATUS Status;
- PFILE_OBJECT FileObject;
- PIO_STACK_LOCATION Stack;
- PMOUNTDEV_NAME Name = NULL;
- PDEVICE_OBJECT DeviceObject;
- IO_STATUS_BLOCK IoStatusBlock;
-
- /* Get the device associated with the name */
- Status = IoGetDeviceObjectPointer(DeviceName,
- FILE_READ_ATTRIBUTES,
- &FileObject,
- &DeviceObject);
- if (!NT_SUCCESS(Status))
- {
- return;
- }
-
- /* Get attached device (will notify it) */
- DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
-
- /* NameSize is the size of the whole MOUNTDEV_NAME struct */
- NameSize = sizeof(USHORT) + SymbolicName->Length;
- Name = AllocatePool(NameSize);
- if (!Name)
- {
- goto Cleanup;
- }
-
- /* Initialize struct */
- Name->NameLength = SymbolicName->Length;
- RtlCopyMemory(Name->Name, SymbolicName->Buffer, SymbolicName->Length);
-
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- /* Cf: SendLinkCreated comment */
- Irp = IoBuildDeviceIoControlRequest(CTL_CODE(MOUNTDEVCONTROLTYPE, 5, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
- DeviceObject,
- Name,
- NameSize,
- NULL,
- 0,
- FALSE,
- &Event,
- &IoStatusBlock);
- /* This one can fail, no one matters */
- if (Irp)
- {
- Stack = IoGetNextIrpStackLocation(Irp);
- Stack->FileObject = FileObject;
-
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
- {
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
- }
- }
-
- /* Then, second one */
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_LINK_DELETED,
- DeviceObject,
- Name,
- NameSize,
- NULL,
- 0,
- FALSE,
- &Event,
- &IoStatusBlock);
- if (!Irp)
- {
- goto Cleanup;
- }
-
- Stack = IoGetNextIrpStackLocation(Irp);
- Stack->FileObject = FileObject;
-
- /* Really notify */
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
- {
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
- }
-
-Cleanup:
- if (Name)
- {
- FreePool(Name);
- }
-
- ObDereferenceObject(DeviceObject);
- ObDereferenceObject(FileObject);
-
- return;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-SymbolicLinkNamesFromUniqueIdCount(IN PWSTR ValueName,
- IN ULONG ValueType,
- IN PVOID ValueData,
- IN ULONG ValueLength,
- IN PVOID Context,
- IN PVOID EntryContext)
-{
- UNICODE_STRING ValueNameString;
- PMOUNTDEV_UNIQUE_ID UniqueId = Context;
-
- if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
- (UniqueId->UniqueIdLength != ValueLength))
- {
- return STATUS_SUCCESS;
- }
-
- if (RtlCompareMemory(UniqueId->UniqueId, ValueData, ValueLength) != ValueLength)
- {
- return STATUS_SUCCESS;
- }
-
- /* That one matched, increase count */
- RtlInitUnicodeString(&ValueNameString, ValueName);
- if (ValueNameString.Length)
- {
- (*((PULONG)EntryContext))++;
- }
-
- return STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-SymbolicLinkNamesFromUniqueIdQuery(IN PWSTR ValueName,
- IN ULONG ValueType,
- IN PVOID ValueData,
- IN ULONG ValueLength,
- IN PVOID Context,
- IN PVOID EntryContext)
-{
- UNICODE_STRING ValueNameString;
- PMOUNTDEV_UNIQUE_ID UniqueId = Context;
- /* Unicode strings table */
- PUNICODE_STRING ReturnString = EntryContext;
-
- if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
- (UniqueId->UniqueIdLength != ValueLength))
- {
- return STATUS_SUCCESS;
- }
-
- if (RtlCompareMemory(UniqueId->UniqueId, ValueData, ValueLength) != ValueLength)
- {
- return STATUS_SUCCESS;
- }
-
- /* Unique ID matches, let's put the symlink */
- RtlInitUnicodeString(&ValueNameString, ValueName);
- if (!ValueNameString.Length)
- {
- return STATUS_SUCCESS;
- }
-
- /* Allocate string to copy */
- ValueNameString.Buffer = AllocatePool(ValueNameString.MaximumLength);
- if (!ValueNameString.Buffer)
- {
- return STATUS_SUCCESS;
- }
-
- /* Copy */
- RtlCopyMemory(ValueNameString.Buffer, ValueName, ValueNameString.Length);
- ValueNameString.Buffer[ValueNameString.Length / sizeof(WCHAR)] = UNICODE_NULL;
-
- while (ReturnString->Length)
- {
- ReturnString++;
- }
-
- /* And return that string */
- *ReturnString = ValueNameString;
-
- return STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-CreateNewVolumeName(OUT PUNICODE_STRING VolumeName,
- IN PGUID VolumeGuid OPTIONAL)
-{
- GUID Guid;
- NTSTATUS Status;
- UNICODE_STRING GuidString;
-
- /* If no GUID was provided, then create one */
- if (!VolumeGuid)
- {
- Status = ExUuidCreate(&Guid);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
- }
- else
- {
- RtlCopyMemory(&Guid, VolumeGuid, sizeof(GUID));
- }
-
- /* Convert GUID to string */
- Status = RtlStringFromGUID(&Guid, &GuidString);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- /* Size for volume namespace, literal GUID, and null char */
- VolumeName->MaximumLength = 0x14 + 0x4C + sizeof(UNICODE_NULL);
- VolumeName->Buffer = AllocatePool(0x14 + 0x4C + sizeof(UNICODE_NULL));
- if (!VolumeName->Buffer)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- }
- else
- {
- RtlCopyUnicodeString(VolumeName, &Volume);
- RtlAppendUnicodeStringToString(VolumeName, &GuidString);
- VolumeName->Buffer[VolumeName->Length / sizeof(WCHAR)] = UNICODE_NULL;
- Status = STATUS_SUCCESS;
- }
-
- ExFreePoolWithTag(GuidString.Buffer, 0);
-
- return Status;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-QuerySymbolicLinkNamesFromStorage(IN PDEVICE_EXTENSION DeviceExtension,
- IN PDEVICE_INFORMATION DeviceInformation,
- IN PUNICODE_STRING SuggestedLinkName,
- IN BOOLEAN UseOnlyIfThereAreNoOtherLinks,
- OUT PUNICODE_STRING * SymLinks,
- OUT PULONG SymLinkCount,
- IN BOOLEAN HasGuid,
- IN LPGUID Guid)
-{
- NTSTATUS Status;
- BOOLEAN WriteNew;
- RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-
- UNREFERENCED_PARAMETER(DeviceExtension);
-
- /* First of all, count links */
- RtlZeroMemory(QueryTable, sizeof(QueryTable));
- QueryTable[0].QueryRoutine = SymbolicLinkNamesFromUniqueIdCount;
- QueryTable[0].EntryContext = SymLinkCount;
- *SymLinkCount = 0;
-
- Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
- DatabasePath,
- QueryTable,
- DeviceInformation->UniqueId,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- *SymLinkCount = 0;
- }
-
- /* Check if we have to write a new one first */
- if (SuggestedLinkName && !IsDriveLetter(SuggestedLinkName) &&
- UseOnlyIfThereAreNoOtherLinks && *SymLinkCount == 0)
- {
- WriteNew = TRUE;
- }
- else
- {
- WriteNew = FALSE;
- }
-
- /* If has GUID, it makes one more link */
- if (HasGuid)
- {
- (*SymLinkCount)++;
- }
-
- if (WriteNew)
- {
- /* Write link */
- RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
- DatabasePath,
- SuggestedLinkName->Buffer,
- REG_BINARY,
- DeviceInformation->UniqueId->UniqueId,
- DeviceInformation->UniqueId->UniqueIdLength);
-
- /* And recount all the needed links */
- RtlZeroMemory(QueryTable, sizeof(QueryTable));
- QueryTable[0].QueryRoutine = SymbolicLinkNamesFromUniqueIdCount;
- QueryTable[0].EntryContext = SymLinkCount;
- *SymLinkCount = 0;
-
- Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
- DatabasePath,
- QueryTable,
- DeviceInformation->UniqueId,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return STATUS_NOT_FOUND;
- }
- }
-
- /* Not links found? */
- if (!*SymLinkCount)
- {
- return STATUS_NOT_FOUND;
- }
-
- /* Allocate a buffer big enough to hold symlinks (table of unicode strings) */
- *SymLinks = AllocatePool(*SymLinkCount * sizeof(UNICODE_STRING));
- if (!*SymLinks)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- /* Prepare to query links */
- RtlZeroMemory(*SymLinks, *SymLinkCount * sizeof(UNICODE_STRING));
- RtlZeroMemory(QueryTable, sizeof(QueryTable));
- QueryTable[0].QueryRoutine = SymbolicLinkNamesFromUniqueIdQuery;
-
- /* No GUID? Keep it that way */
- if (!HasGuid)
- {
- QueryTable[0].EntryContext = *SymLinks;
- }
- /* Otherwise, first create volume name */
- else
- {
- Status = CreateNewVolumeName(SymLinks[0], Guid);
- if (!NT_SUCCESS(Status))
- {
- FreePool(*SymLinks);
- return Status;
- }
-
- /* Skip first link (ours) */
- QueryTable[0].EntryContext = *SymLinks + 1;
- }
-
- /* Now, query */
- RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
- DatabasePath,
- QueryTable,
- DeviceInformation->UniqueId,
- NULL);
-
- return STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-PSAVED_LINK_INFORMATION
-RemoveSavedLinks(IN PDEVICE_EXTENSION DeviceExtension,
- IN PMOUNTDEV_UNIQUE_ID UniqueId)
-{
- PLIST_ENTRY NextEntry;
- PSAVED_LINK_INFORMATION SavedLinkInformation;
-
- /* No saved links? Easy! */
- if (IsListEmpty(&(DeviceExtension->SavedLinksListHead)))
- {
- return NULL;
- }
-
- /* Now, browse saved links */
- for (NextEntry = DeviceExtension->SavedLinksListHead.Flink;
- NextEntry != &(DeviceExtension->SavedLinksListHead);
- NextEntry = NextEntry->Flink)
- {
- SavedLinkInformation = CONTAINING_RECORD(NextEntry,
- SAVED_LINK_INFORMATION,
- SavedLinksListEntry);
-
- /* Find the one that matches */
- if (SavedLinkInformation->UniqueId->UniqueIdLength == UniqueId->UniqueIdLength)
- {
- if (RtlCompareMemory(SavedLinkInformation->UniqueId->UniqueId,
- UniqueId->UniqueId,
- UniqueId->UniqueIdLength) ==
- UniqueId->UniqueIdLength)
- {
- /* Remove it and return it */
- RemoveEntryList(&(SavedLinkInformation->SavedLinksListEntry));
- return SavedLinkInformation;
- }
- }
- }
-
- /* None found (none removed) */
- return NULL;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-QuerySuggestedLinkName(IN PUNICODE_STRING SymbolicName,
- OUT PUNICODE_STRING SuggestedLinkName,
- OUT PBOOLEAN UseOnlyIfThereAreNoOtherLinks)
-{
- PIRP Irp;
- KEVENT Event;
- NTSTATUS Status;
- USHORT NameLength;
- PFILE_OBJECT FileObject;
- PDEVICE_OBJECT DeviceObject;
- IO_STATUS_BLOCK IoStatusBlock;
- PIO_STACK_LOCATION IoStackLocation;
- PMOUNTDEV_SUGGESTED_LINK_NAME IoCtlSuggested;
-
- /* First, get device */
- Status = IoGetDeviceObjectPointer(SymbolicName,
- FILE_READ_ATTRIBUTES,
- &FileObject,
- &DeviceObject);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- /* Then, get attached device */
- DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
-
- /* Then, prepare buffer to query suggested name */
- IoCtlSuggested = AllocatePool(sizeof(MOUNTDEV_SUGGESTED_LINK_NAME));
- if (!IoCtlSuggested)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Dereference;
- }
-
- /* Prepare request */
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME,
- DeviceObject,
- NULL,
- 0,
- IoCtlSuggested,
- sizeof(MOUNTDEV_SUGGESTED_LINK_NAME),
- FALSE,
- &Event,
- &IoStatusBlock);
- if (!Irp)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Release;
- }
-
- IoStackLocation = IoGetNextIrpStackLocation(Irp);
- IoStackLocation->FileObject = FileObject;
-
- /* And ask */
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
- {
- KeWaitForSingleObject(&Event, Executive, KernelMode,
- FALSE, NULL);
- Status = IoStatusBlock.Status;
- }
-
- /* Overflow? Normal */
- if (Status == STATUS_BUFFER_OVERFLOW)
- {
- /* Reallocate big enough buffer */
- NameLength = IoCtlSuggested->NameLength + sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
- FreePool(IoCtlSuggested);
-
- IoCtlSuggested = AllocatePool(NameLength);
- if (!IoCtlSuggested)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Dereference;
- }
-
- /* And reask */
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME,
- DeviceObject,
- NULL,
- 0,
- IoCtlSuggested,
- NameLength,
- FALSE,
- &Event,
- &IoStatusBlock);
- if (!Irp)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Release;
- }
-
- IoStackLocation = IoGetNextIrpStackLocation(Irp);
- IoStackLocation->FileObject = FileObject;
-
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
- {
- KeWaitForSingleObject(&Event, Executive, KernelMode,
- FALSE, NULL);
- Status = IoStatusBlock.Status;
- }
- }
-
- if (!NT_SUCCESS(Status))
- {
- goto Release;
- }
-
- /* Now we have suggested name, copy it */
- SuggestedLinkName->Length = IoCtlSuggested->NameLength;
- SuggestedLinkName->MaximumLength = IoCtlSuggested->NameLength + sizeof(UNICODE_NULL);
- SuggestedLinkName->Buffer = AllocatePool(IoCtlSuggested->NameLength + sizeof(UNICODE_NULL));
- if (!SuggestedLinkName->Buffer)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- }
- else
- {
- RtlCopyMemory(SuggestedLinkName->Buffer, IoCtlSuggested->Name, IoCtlSuggested->NameLength);
- SuggestedLinkName->Buffer[SuggestedLinkName->Length / sizeof(WCHAR)] = UNICODE_NULL;
- }
-
- /* Also return its priority */
- *UseOnlyIfThereAreNoOtherLinks = IoCtlSuggested->UseOnlyIfThereAreNoOtherLinks;
-
-Release:
- FreePool(IoCtlSuggested);
-
-Dereference:
- ObDereferenceObject(DeviceObject);
- ObDereferenceObject(FileObject);
-
- return Status;
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-RedirectSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation,
- IN PUNICODE_STRING DosName,
- IN PUNICODE_STRING NewLink)
-{
- PLIST_ENTRY NextEntry;
- PSYMLINK_INFORMATION SymlinkInformation;
-
- /* Find the link */
- for (NextEntry = SavedLinkInformation->SymbolicLinksListHead.Flink;
- NextEntry != &(SavedLinkInformation->SymbolicLinksListHead);
- NextEntry = NextEntry->Flink)
- {
- SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
-
- if (!RtlEqualUnicodeString(DosName, &(SymlinkInformation->Name), TRUE))
- {
- /* Delete old link */
- GlobalDeleteSymbolicLink(DosName);
- /* Set its new location */
- GlobalCreateSymbolicLink(DosName, NewLink);
-
- /* And remove it from the list (not valid any more) */
- RemoveEntryList(&(SymlinkInformation->SymbolicLinksListEntry));
- FreePool(SymlinkInformation->Name.Buffer);
- FreePool(SymlinkInformation);
-
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/*
- * @implemented
- */
-VOID
-DeleteSymbolicLinkNameFromMemory(IN PDEVICE_EXTENSION DeviceExtension,
- IN PUNICODE_STRING SymbolicLink,
- IN BOOLEAN MarkOffline)
-{
- PLIST_ENTRY DeviceEntry, SymbolEntry;
- PDEVICE_INFORMATION DeviceInformation;
- PSYMLINK_INFORMATION SymlinkInformation;
-
- /* First of all, ensure we have devices */
- if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
- {
- return;
- }
-
- /* Then, look for the symbolic name */
- for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
- DeviceEntry != &(DeviceExtension->DeviceListHead);
- DeviceEntry = DeviceEntry->Flink)
- {
- DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
-
- for (SymbolEntry = DeviceInformation->SymbolicLinksListHead.Flink;
- SymbolEntry != &(DeviceInformation->SymbolicLinksListHead);
- SymbolEntry = SymbolEntry->Flink)
- {
- SymlinkInformation = CONTAINING_RECORD(SymbolEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
-
- /* One we have found it */
- if (RtlCompareUnicodeString(SymbolicLink, &(SymlinkInformation->Name), TRUE) == 0)
- {
- /* Check if caller just want it to be offline */
- if (MarkOffline)
- {
- SymlinkInformation->Online = FALSE;
- }
- else
- {
- /* If not, delete it & notify */
- SendLinkDeleted(&(DeviceInformation->SymbolicName), SymbolicLink);
- RemoveEntryList(&(SymlinkInformation->SymbolicLinksListEntry));
-
- FreePool(SymlinkInformation->Name.Buffer);
- FreePool(SymlinkInformation);
- }
-
- /* No need to go farther */
- return;
- }
- }
- }
-
- return;
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-IsDriveLetter(PUNICODE_STRING SymbolicName)
-{
- WCHAR Letter, Colon;
-
- /* We must have a precise length */
- if (SymbolicName->Length != DosDevices.Length + 2 * sizeof(WCHAR))
- {
- return FALSE;
- }
-
- /* Must start with the DosDevices prefix */
- if (!RtlPrefixUnicodeString(&DosDevices, SymbolicName, TRUE))
- {
- return FALSE;
- }
-
- /* Check if letter is correct */
- Letter = SymbolicName->Buffer[DosDevices.Length / sizeof(WCHAR)];
- if ((Letter < L'A' || Letter > L'Z') && Letter != (WCHAR)-1)
- {
- return FALSE;
- }
-
- /* And finally it must end with a colon */
- Colon = SymbolicName->Buffer[DosDevices.Length / sizeof(WCHAR) + 1];
- if (Colon != L':')
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-MountMgrQuerySymbolicLink(IN PUNICODE_STRING SymbolicName,
- IN OUT PUNICODE_STRING LinkTarget)
-{
- NTSTATUS Status;
- HANDLE LinkHandle;
- OBJECT_ATTRIBUTES ObjectAttributes;
-
- /* Open the symbolic link */
- InitializeObjectAttributes(&ObjectAttributes,
- SymbolicName,
- OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
-
- Status = ZwOpenSymbolicLinkObject(&LinkHandle,
- GENERIC_READ,
- &ObjectAttributes);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- /* Query its target */
- Status = ZwQuerySymbolicLinkObject(LinkHandle,
- LinkTarget,
- NULL);
-
- ZwClose(LinkHandle);
-
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- if (LinkTarget->Length <= sizeof(WCHAR))
- {
- return Status;
- }
-
- /* If it's not finished by \, just return */
- if (LinkTarget->Buffer[LinkTarget->Length / sizeof(WCHAR) - 1] != L'\\')
- {
- return Status;
- }
-
- /* Otherwise, ensure to drop the tailing \ */
- LinkTarget->Length -= sizeof(WCHAR);
- LinkTarget->Buffer[LinkTarget->Length / sizeof(WCHAR)] = UNICODE_NULL;
-
- return Status;
-}