Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797/* * 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/device.c * PURPOSE: Mount Manager - Device Control * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org) */
#include "mntmgr.h"
#define MAX_DEVICES 0x3E8 /* Matches 1000 devices */
#define NDEBUG#include <debug.h>
/* * @implemented */NTSTATUSMountMgrChangeNotify(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ KIRQL OldIrql; NTSTATUS Status; PIO_STACK_LOCATION Stack; PMOUNTMGR_CHANGE_NOTIFY_INFO ChangeNotify;
/* Get the I/O buffer */ Stack = IoGetCurrentIrpStackLocation(Irp); ChangeNotify = (PMOUNTMGR_CHANGE_NOTIFY_INFO)Irp->AssociatedIrp.SystemBuffer;
/* Validate it */ if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO) || Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO)) { return STATUS_INVALID_PARAMETER; }
/* If epic number doesn't match, just return now one */ if (DeviceExtension->EpicNumber != ChangeNotify->EpicNumber) { ChangeNotify->EpicNumber = DeviceExtension->EpicNumber; Irp->IoStatus.Information = sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO); return STATUS_SUCCESS; }
/* If IRP is to be canceled, forget about that */ IoAcquireCancelSpinLock(&OldIrql); if (Irp->Cancel) { Status = STATUS_CANCELLED; } /* Otherwise queue the IRP to be notified with the next epic number change */ else { InsertTailList(&(DeviceExtension->IrpListHead), &(Irp->Tail.Overlay.ListEntry)); IoMarkIrpPending(Irp); IoSetCancelRoutine(Irp, MountMgrCancel); Status = STATUS_PENDING; } IoReleaseCancelSpinLock(OldIrql);
return Status;}
/* * @implemented */NTSTATUSMountmgrWriteNoAutoMount(IN PDEVICE_EXTENSION DeviceExtension){ ULONG Value = DeviceExtension->NoAutoMount;
return RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, DeviceExtension->RegistryPath.Buffer, L"NoAutoMount", REG_DWORD, &Value, sizeof(Value));}
/* * @implemented */NTSTATUSMountMgrSetAutoMount(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ PIO_STACK_LOCATION Stack; PMOUNTMGR_SET_AUTO_MOUNT SetState;
Stack = IoGetCurrentIrpStackLocation(Irp);
if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_SET_AUTO_MOUNT)) { Irp->IoStatus.Information = 0; return STATUS_INVALID_PARAMETER; }
/* Change the state only if there is a real difference * with the user-provided NewState (normalized) */ SetState = (PMOUNTMGR_SET_AUTO_MOUNT)Irp->AssociatedIrp.SystemBuffer; if ((SetState->NewState != Enabled) == DeviceExtension->NoAutoMount) { Irp->IoStatus.Information = 0; return STATUS_SUCCESS; }
/* Set new state */ DeviceExtension->NoAutoMount = (SetState->NewState != Enabled); Irp->IoStatus.Information = 0; return MountmgrWriteNoAutoMount(DeviceExtension);}
/* * @implemented */NTSTATUSMountMgrQueryAutoMount(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ PIO_STACK_LOCATION Stack; PMOUNTMGR_QUERY_AUTO_MOUNT QueryState;
Stack = IoGetCurrentIrpStackLocation(Irp);
if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_QUERY_AUTO_MOUNT)) { Irp->IoStatus.Information = 0; return STATUS_INVALID_PARAMETER; }
QueryState = (PMOUNTMGR_QUERY_AUTO_MOUNT)Irp->AssociatedIrp.SystemBuffer; QueryState->CurrentState = !DeviceExtension->NoAutoMount; Irp->IoStatus.Information = sizeof(MOUNTMGR_QUERY_AUTO_MOUNT);
return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIScrubRegistryRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext){ NTSTATUS Status; PLIST_ENTRY NextEntry; PDEVICE_INFORMATION DeviceInfo; PBOOLEAN Continue = EntryContext; PDEVICE_EXTENSION DeviceExtension = Context;
if (ValueType != REG_BINARY) { return STATUS_SUCCESS; }
/* Delete values for devices that don't have the matching unique ID */ if (!IsListEmpty(&(DeviceExtension->DeviceListHead))) { for (NextEntry = DeviceExtension->DeviceListHead.Flink; NextEntry != &(DeviceExtension->DeviceListHead); NextEntry = NextEntry->Flink) { DeviceInfo = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
if (!DeviceInfo->UniqueId || DeviceInfo->UniqueId->UniqueIdLength != ValueLength) { continue; }
if (RtlCompareMemory(DeviceInfo->UniqueId->UniqueId, ValueData, ValueLength) == ValueLength) { return STATUS_SUCCESS; } } }
/* Wrong unique ID, scrub it */ Status = RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, ValueName); if (!NT_SUCCESS(Status)) { *Continue = TRUE; return STATUS_UNSUCCESSFUL; }
*Continue = FALSE; return Status;}
/* * @implemented */NTSTATUSMountMgrScrubRegistry(IN PDEVICE_EXTENSION DeviceExtension){ NTSTATUS Status; BOOLEAN Continue; RTL_QUERY_REGISTRY_TABLE QueryTable[2];
do { RtlZeroMemory(QueryTable, sizeof(QueryTable)); QueryTable[0].QueryRoutine = ScrubRegistryRoutine; QueryTable[0].EntryContext = &Continue; Continue = FALSE;
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, DatabasePath, QueryTable, DeviceExtension, NULL); } while (Continue);
return Status;}
/* * @implemented */NTSTATUSMountMgrCreatePoint(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ ULONG MaxLength; PIO_STACK_LOCATION Stack; PMOUNTMGR_CREATE_POINT_INPUT Point; UNICODE_STRING DeviceName, SymbolicName;
Stack = IoGetCurrentIrpStackLocation(Irp);
if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_CREATE_POINT_INPUT)) { return STATUS_INVALID_PARAMETER; }
Point = (PMOUNTMGR_CREATE_POINT_INPUT)Irp->AssociatedIrp.SystemBuffer;
MaxLength = MAX((Point->DeviceNameOffset + Point->DeviceNameLength), (Point->SymbolicLinkNameLength + Point->SymbolicLinkNameOffset)); if (MaxLength > Stack->Parameters.DeviceIoControl.InputBufferLength) { return STATUS_INVALID_PARAMETER; }
/* Get all the strings and call the worker */ SymbolicName.Length = Point->SymbolicLinkNameLength; SymbolicName.MaximumLength = Point->SymbolicLinkNameLength; DeviceName.Length = Point->DeviceNameLength; DeviceName.MaximumLength = Point->DeviceNameLength; SymbolicName.Buffer = (PVOID)((ULONG_PTR)Point + Point->SymbolicLinkNameOffset); DeviceName.Buffer = (PVOID)((ULONG_PTR)Point + Point->DeviceNameOffset);
return MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &DeviceName);}
/* * @implemented */NTSTATUSMountMgrCheckUnprocessedVolumes(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ PLIST_ENTRY NextEntry; PDEVICE_INFORMATION DeviceInformation; NTSTATUS ArrivalStatus, Status = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(Irp);
/* No offline volumes, nothing more to do */ if (IsListEmpty(&(DeviceExtension->OfflineDeviceListHead))) { KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); return STATUS_SUCCESS; }
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
/* Reactivate all the offline volumes */ while (!IsListEmpty(&(DeviceExtension->OfflineDeviceListHead))) { NextEntry = RemoveHeadList(&(DeviceExtension->OfflineDeviceListHead)); DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
ArrivalStatus = MountMgrMountedDeviceArrival(DeviceExtension, &(DeviceInformation->SymbolicName), DeviceInformation->ManuallyRegistered); /* Then, remove them dead information */ MountMgrFreeDeadDeviceInfo(DeviceInformation);
if (NT_SUCCESS(Status)) { Status = ArrivalStatus; } }
return Status;}
/* * @implemented */BOOLEANIsFtVolume(IN PUNICODE_STRING SymbolicName){ NTSTATUS Status; PFILE_OBJECT FileObject; PARTITION_INFORMATION PartitionInfo; PDEVICE_OBJECT DeviceObject, FileDeviceObject;
/* Get device object */ Status = IoGetDeviceObjectPointer(SymbolicName, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); if (!NT_SUCCESS(Status)) return FALSE;
/* Get attached device */ FileDeviceObject = FileObject->DeviceObject; DeviceObject = IoGetAttachedDeviceReference(FileDeviceObject);
/* FT volume can't be removable */ if (FileDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { ObDereferenceObject(DeviceObject); ObDereferenceObject(FileObject); return FALSE; }
ObDereferenceObject(FileObject);
/* Get partition information */ Status = MountMgrSendSyncDeviceIoCtl(IOCTL_DISK_GET_PARTITION_INFO, DeviceObject, NULL, 0, &PartitionInfo, sizeof(PartitionInfo), NULL);
ObDereferenceObject(DeviceObject); if (!NT_SUCCESS(Status)) return FALSE;
/* Check if this is a FT volume */ return IsFTPartition(PartitionInfo.PartitionType);}
/* * @implemented */VOIDProcessSuggestedDriveLetters(IN PDEVICE_EXTENSION DeviceExtension){ WCHAR NameBuffer[DRIVE_LETTER_LENGTH / sizeof(WCHAR)]; PLIST_ENTRY NextEntry; UNICODE_STRING SymbolicName; PDEVICE_INFORMATION DeviceInformation;
/* No devices? Nothing to do! */ if (IsListEmpty(&(DeviceExtension->DeviceListHead))) { return; }
/* For all the devices */ for (NextEntry = DeviceExtension->DeviceListHead.Flink; NextEntry != &(DeviceExtension->DeviceListHead); NextEntry = NextEntry->Flink) { DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
/* If no drive letter */ if (DeviceInformation->SuggestedDriveLetter == (UCHAR)-1) { /* Ensure it has no entry yet */ if (!HasDriveLetter(DeviceInformation) && !HasNoDriveLetterEntry(DeviceInformation->UniqueId)) { /* And create one */ CreateNoDriveLetterEntry(DeviceInformation->UniqueId); }
DeviceInformation->SuggestedDriveLetter = 0; } /* Suggested letter & no entry */ else if (DeviceInformation->SuggestedDriveLetter && !HasNoDriveLetterEntry(DeviceInformation->UniqueId)) { /* Just create a mount point */ SymbolicName.Buffer = NameBuffer; RtlCopyMemory(NameBuffer, DosDevices.Buffer, DosDevices.Length); NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter; NameBuffer[COLON_POSITION] = L':'; SymbolicName.Length = SymbolicName.MaximumLength = DRIVE_LETTER_LENGTH;
MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &(DeviceInformation->DeviceName)); } }}
/* * @implemented */NTSTATUSMountMgrNextDriveLetterWorker(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING DeviceName, OUT PMOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInfo){ NTSTATUS Status; UCHAR DriveLetter; PLIST_ENTRY NextEntry; PMOUNTDEV_UNIQUE_ID UniqueId; BOOLEAN Removable, GptDriveLetter; PDEVICE_INFORMATION DeviceInformation; WCHAR NameBuffer[DRIVE_LETTER_LENGTH]; PSYMLINK_INFORMATION SymlinkInformation; UNICODE_STRING TargetDeviceName, SymbolicName;
/* First, process suggested letters */ if (!DeviceExtension->ProcessedSuggestions) { ProcessSuggestedDriveLetters(DeviceExtension); DeviceExtension->ProcessedSuggestions = TRUE; }
/* Then, get information about the device */ Status = QueryDeviceInformation(DeviceName, &TargetDeviceName, NULL, &Removable, &GptDriveLetter, NULL, NULL, NULL); if (!NT_SUCCESS(Status)) { return Status; }
/* Ensure we have such device */ NextEntry = DeviceExtension->DeviceListHead.Flink; while (NextEntry != &(DeviceExtension->DeviceListHead)) { DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
if (RtlCompareUnicodeString(&(DeviceInformation->DeviceName), &TargetDeviceName, TRUE) == 0) { break; }
NextEntry = NextEntry->Flink; }
if (NextEntry == &(DeviceExtension->DeviceListHead)) { FreePool(TargetDeviceName.Buffer); return STATUS_OBJECT_NAME_NOT_FOUND; }
/* Now, assume we will assign a letter */ DeviceInformation->LetterAssigned = DriveLetterInfo->DriveLetterWasAssigned = TRUE;
/* Browse all the symlinks to check if there is already a drive letter */ NextEntry = DeviceInformation->SymbolicLinksListHead.Flink; while (NextEntry != &(DeviceInformation->SymbolicLinksListHead)) { SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
/* If this is a drive letter and it is online, forget about new drive letter */ if (IsDriveLetter(&(SymlinkInformation->Name)) && SymlinkInformation->Online) { DriveLetterInfo->DriveLetterWasAssigned = FALSE; DriveLetterInfo->CurrentDriveLetter = (CHAR)SymlinkInformation->Name.Buffer[LETTER_POSITION]; break; }
NextEntry = NextEntry->Flink; }
/* If we didn't find a drive letter online, ensure this is not * a no-drive entry by querying GPT attributes & database */ if (NextEntry == &(DeviceInformation->SymbolicLinksListHead)) { if (!GptDriveLetter || HasNoDriveLetterEntry(DeviceInformation->UniqueId)) { DriveLetterInfo->DriveLetterWasAssigned = FALSE; DriveLetterInfo->CurrentDriveLetter = 0; goto Release; } }
/* If automount is disabled, and the device is not removable * but needs a drive letter, don't assign one and bail out */ if (DeviceExtension->NoAutoMount && !Removable) { if (DriveLetterInfo->DriveLetterWasAssigned) { DriveLetterInfo->DriveLetterWasAssigned = FALSE; DriveLetterInfo->CurrentDriveLetter = 0; goto Release; } }
/* Stop now if we don't need to assign the drive a letter */ if (!DriveLetterInfo->DriveLetterWasAssigned) goto Release;
/* Now everything is fine, begin drive letter assignment */
if (RtlPrefixUnicodeString(&DeviceFloppy, &TargetDeviceName, TRUE)) { /* If the device is a floppy, start with letter A */ DriveLetter = 'A'; } else if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE)) { /* If the device is a CD-ROM, start with letter D */ DriveLetter = 'D'; } else { /* Finally, if it's a disk, use C */ DriveLetter = 'C'; }
/* We cannot set NO drive letter */ ASSERT(DeviceInformation->SuggestedDriveLetter != (UCHAR)-1);
/* If we don't have suggested letter but it's a FT volume, fail */ if (!DeviceInformation->SuggestedDriveLetter && IsFtVolume(&(DeviceInformation->DeviceName))) { DriveLetterInfo->DriveLetterWasAssigned = FALSE; DriveLetterInfo->CurrentDriveLetter = 0; goto Release; }
/* Prepare buffer */ RtlCopyMemory(NameBuffer, DosDevices.Buffer, DosDevices.Length); NameBuffer[COLON_POSITION] = L':'; SymbolicName.Buffer = NameBuffer; SymbolicName.Length = SymbolicName.MaximumLength = DRIVE_LETTER_LENGTH;
/* It's all prepared, create mount point */ if (DeviceInformation->SuggestedDriveLetter) { DriveLetterInfo->CurrentDriveLetter = DeviceInformation->SuggestedDriveLetter; NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter;
Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName); if (NT_SUCCESS(Status)) { goto Release; } }
/* It failed with this letter... Try another one! */ for (DriveLetterInfo->CurrentDriveLetter = DriveLetter; DriveLetterInfo->CurrentDriveLetter <= L'Z'; DriveLetterInfo->CurrentDriveLetter++) { NameBuffer[LETTER_POSITION] = DriveLetterInfo->CurrentDriveLetter;
Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName); if (NT_SUCCESS(Status)) { break; } }
/* We failed setting a letter */ if (DriveLetterInfo->CurrentDriveLetter > L'Z') { DriveLetterInfo->DriveLetterWasAssigned = FALSE; DriveLetterInfo->CurrentDriveLetter = 0;
/* Try at least to add a no drive letter entry */ Status = QueryDeviceInformation(&TargetDeviceName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL); if (NT_SUCCESS(Status)) { CreateNoDriveLetterEntry(UniqueId); FreePool(UniqueId); } }
Release: FreePool(TargetDeviceName.Buffer);
return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSMountMgrNextDriveLetter(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ NTSTATUS Status; PIO_STACK_LOCATION Stack; UNICODE_STRING DeviceName; PMOUNTMGR_DRIVE_LETTER_TARGET DriveLetterTarget; MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Validate input */ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) || Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION)) { return STATUS_INVALID_PARAMETER; }
DriveLetterTarget = (PMOUNTMGR_DRIVE_LETTER_TARGET)Irp->AssociatedIrp.SystemBuffer; if (FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName) + DriveLetterTarget->DeviceNameLength > Stack->Parameters.DeviceIoControl.InputBufferLength) { return STATUS_INVALID_PARAMETER; }
/* Call the worker */ DeviceName.Buffer = DriveLetterTarget->DeviceName; DeviceName.Length = DeviceName.MaximumLength = DriveLetterTarget->DeviceNameLength;
Status = MountMgrNextDriveLetterWorker(DeviceExtension, &DeviceName, &DriveLetterInformation); if (NT_SUCCESS(Status)) { *(PMOUNTMGR_DRIVE_LETTER_INFORMATION)Irp->AssociatedIrp.SystemBuffer = DriveLetterInformation; Irp->IoStatus.Information = sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION); }
return Status;}
/* * @implemented */NTSTATUSNTAPIMountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext){ UNICODE_STRING ValueString; PUNICODE_STRING SystemVolumeName;
UNREFERENCED_PARAMETER(ValueName); UNREFERENCED_PARAMETER(ValueLength); UNREFERENCED_PARAMETER(EntryContext);
if (ValueType != REG_SZ) { return STATUS_SUCCESS; }
RtlInitUnicodeString(&ValueString, ValueData); SystemVolumeName = Context;
/* Return a string containing system volume name */ SystemVolumeName->Length = ValueString.Length; SystemVolumeName->MaximumLength = ValueString.Length + sizeof(WCHAR); SystemVolumeName->Buffer = AllocatePool(SystemVolumeName->MaximumLength); if (SystemVolumeName->Buffer) { RtlCopyMemory(SystemVolumeName->Buffer, ValueData, ValueString.Length); SystemVolumeName->Buffer[ValueString.Length / sizeof(WCHAR)] = UNICODE_NULL; }
return STATUS_SUCCESS;
}
/* * @implemented */NTSTATUSMountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName){ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
RtlZeroMemory(QueryTable, sizeof(QueryTable)); QueryTable[0].QueryRoutine = MountMgrQuerySystemVolumeNameQueryRoutine; QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].Name = L"SystemPartition";
SystemVolumeName->Buffer = NULL;
RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\System\\Setup", QueryTable, SystemVolumeName, NULL);
if (SystemVolumeName->Buffer) { return STATUS_SUCCESS; }
return STATUS_UNSUCCESSFUL;}
/* * @implemented */VOIDMountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension){ NTSTATUS Status; PLIST_ENTRY NextEntry; UNICODE_STRING SystemVolumeName; PDEVICE_INFORMATION DeviceInformation; MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
/* First, get system volume name */ Status = MountMgrQuerySystemVolumeName(&SystemVolumeName);
/* If there are no device, it's all done */ if (IsListEmpty(&(DeviceExtension->DeviceListHead))) { if (NT_SUCCESS(Status)) { FreePool(SystemVolumeName.Buffer); }
return; }
/* Now, for all the devices... */ for (NextEntry = DeviceExtension->DeviceListHead.Flink; NextEntry != &(DeviceExtension->DeviceListHead); NextEntry = NextEntry->Flink) { DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
/* If the device doesn't have a letter assigned, do it! */ if (!DeviceInformation->LetterAssigned) { MountMgrNextDriveLetterWorker(DeviceExtension, &(DeviceInformation->DeviceName), &DriveLetterInformation); }
/* If it's the system volume */ if (NT_SUCCESS(Status) && RtlEqualUnicodeString(&SystemVolumeName, &(DeviceInformation->DeviceName), TRUE)) { /* Keep track of it */ DeviceExtension->DriveLetterData = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); if (DeviceExtension->DriveLetterData) { RtlCopyMemory(DeviceExtension->DriveLetterData, DeviceInformation->UniqueId, DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); }
/* Ensure it gets mounted if automount is disabled */ if (DeviceExtension->NoAutoMount) { /* Temporarily re-enable automount for the * worker to mount and set a drive letter */ DeviceExtension->NoAutoMount = FALSE;
MountMgrNextDriveLetterWorker(DeviceExtension, &(DeviceInformation->DeviceName), &DriveLetterInformation);
/* And re-disable automount */ DeviceExtension->NoAutoMount = TRUE; } } }
if (NT_SUCCESS(Status)) { FreePool(SystemVolumeName.Buffer); }}
/* * @implemented */NTSTATUSMountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ NTSTATUS Status; ULONG DevicesFound; PIO_STACK_LOCATION Stack; PLIST_ENTRY SymlinksEntry; UNICODE_STRING SymbolicName; PMOUNTMGR_TARGET_NAME Target; PMOUNTMGR_VOLUME_PATHS Output; PWSTR DeviceString, OldBuffer; USHORT DeviceLength, OldLength; PDEVICE_INFORMATION DeviceInformation; PSYMLINK_INFORMATION SymlinkInformation; PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Validate input size */ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) { return STATUS_INVALID_PARAMETER; }
/* Ensure we have received UNICODE_STRING */ Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; if (Target->DeviceNameLength & 1) { return STATUS_INVALID_PARAMETER; }
/* Validate the entry structure size */ if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength > Stack->Parameters.DeviceIoControl.InputBufferLength) { return STATUS_INVALID_PARAMETER; }
/* Ensure we can at least return needed size */ if (Stack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz)) { return STATUS_INVALID_PARAMETER; }
/* Construct string for query */ SymbolicName.Length = SymbolicName.MaximumLength = Target->DeviceNameLength; SymbolicName.Buffer = Target->DeviceName;
/* Find device with our info */ Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation); if (!NT_SUCCESS(Status)) { return Status; }
DeviceLength = 0; DeviceString = NULL; DevicesFound = 0;
/* Try to find associated device info */ while (TRUE) { for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink; SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead); SymlinksEntry = SymlinksEntry->Flink) { SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
/* Try to find with drive letter */ if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online) { break; } }
/* If we've found a device via drive letter, do default processing */ if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead)) break;
/* If it doesn't have an associated device, go to fallback method */ if (IsListEmpty(&DeviceInformation->AssociatedDevicesHead)) goto TryWithVolumeName;
/* Create a string with the information about the device */ AssociatedDevice = CONTAINING_RECORD(&(DeviceInformation->AssociatedDevicesHead), ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); OldLength = DeviceLength; OldBuffer = DeviceString; DeviceLength += AssociatedDevice->String.Length; DeviceString = AllocatePool(DeviceLength); if (!DeviceString) { if (OldBuffer) { FreePool(OldBuffer); }
return STATUS_INSUFFICIENT_RESOURCES; }
/* Store our info and previous if any */ RtlCopyMemory(DeviceString, AssociatedDevice->String.Buffer, AssociatedDevice->String.Length); if (OldBuffer) { RtlCopyMemory(&DeviceString[AssociatedDevice->String.Length / sizeof(WCHAR)], OldBuffer, OldLength); FreePool(OldBuffer); }
/* Count and continue looking */ ++DevicesFound; DeviceInformation = AssociatedDevice->DeviceInformation;
/* If too many devices, try another way */ if (DevicesFound > MAX_DEVICES) /* 1000 */ { goto TryWithVolumeName; } }
/* Reallocate our string, so that we can prepend disk letter */ OldBuffer = DeviceString; OldLength = DeviceLength; DeviceLength += 2 * sizeof(WCHAR); DeviceString = AllocatePool(DeviceLength); if (!DeviceString) { if (OldBuffer) { FreePool(OldBuffer); }
return STATUS_INSUFFICIENT_RESOURCES; }
/* Get the letter */ DeviceString[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION]; DeviceString[1] = L':';
/* And copy the rest */ if (OldBuffer) { RtlCopyMemory(&DeviceString[2], OldBuffer, OldLength); FreePool(OldBuffer); }
TryWithVolumeName: /* If we didn't find anything, try differently */ if (DeviceLength < 2 * sizeof(WCHAR) || DeviceString[1] != L':') { if (DeviceString) { FreePool(DeviceString); DeviceString = NULL; DeviceLength = 0; }
/* Try to find a volume name matching */ for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink; SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead); SymlinksEntry = SymlinksEntry->Flink) { SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
if (MOUNTMGR_IS_VOLUME_NAME(&SymlinkInformation->Name)) { break; } }
/* If found copy */ if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead)) { DeviceLength = SymlinkInformation->Name.Length; DeviceString = AllocatePool(DeviceLength); if (!DeviceString) { return STATUS_INSUFFICIENT_RESOURCES; }
RtlCopyMemory(DeviceString, SymlinkInformation->Name.Buffer, DeviceLength); /* Ensure we are in the Win32 namespace; [1] can be '?' */ DeviceString[1] = L'\\'; } }
/* If we didn't find something, fail */ if (!DeviceString) return STATUS_NOT_FOUND;
/* Get the output buffer */ Output = (PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer;
/* At least, we will return our length */ Output->MultiSzLength = DeviceLength + 2 * sizeof(UNICODE_NULL); Irp->IoStatus.Information = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz) + Output->MultiSzLength;
/* If we have enough room for copying the string */ if (Irp->IoStatus.Information <= Stack->Parameters.DeviceIoControl.OutputBufferLength) { /* Copy it */ if (DeviceLength) { RtlCopyMemory(Output->MultiSz, DeviceString, DeviceLength); }
/* And double-NUL at its end - this is needed in case of * multiple paths which are separated by a single NUL */ FreePool(DeviceString); Output->MultiSz[DeviceLength / sizeof(WCHAR)] = UNICODE_NULL; Output->MultiSz[DeviceLength / sizeof(WCHAR) + 1] = UNICODE_NULL;
return STATUS_SUCCESS; } else { /* Just return the size needed and leave */ FreePool(DeviceString); Irp->IoStatus.Information = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz); return STATUS_BUFFER_OVERFLOW; }}
/* * @implemented */NTSTATUSMountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry, IN PDEVICE_INFORMATION DeviceInformation, OUT PBOOLEAN Invalid){ HANDLE Handle; NTSTATUS Status; PLIST_ENTRY SymlinksEntry; IO_STATUS_BLOCK IoStatusBlock; PREPARSE_DATA_BUFFER ReparseData; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING FullName, SubstituteName; PSYMLINK_INFORMATION SymlinkInformation;
/* Initialize & allocate a string big enough to contain our complete mount point name */ FullName.Length = 0; FullName.MaximumLength = AssociatedDeviceEntry->String.Length + AssociatedDeviceEntry->DeviceInformation->DeviceName.Length + sizeof(WCHAR) + sizeof(UNICODE_NULL); FullName.Buffer = AllocatePool(FullName.MaximumLength); if (!FullName.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; }
/* Create the path */ RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->DeviceInformation->DeviceName); FullName.Buffer[FullName.Length / sizeof(WCHAR)] = L'\\'; RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->String); FullName.Buffer[FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
/* Open it to query the reparse point */ InitializeObjectAttributes(&ObjectAttributes, &FullName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenFile(&Handle, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT); FreePool(FullName.Buffer);
if (!NT_SUCCESS(Status)) { *Invalid = TRUE; return STATUS_SUCCESS; }
/* Allocate a buffer big enough to read reparse data */ ReparseData = AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); if (ReparseData == NULL) { ZwClose(Handle); return STATUS_INSUFFICIENT_RESOURCES; }
/* Query reparse data */ Status = ZwFsControlFile(Handle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_GET_REPARSE_POINT, NULL, 0, ReparseData, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); ZwClose(Handle);
if (!NT_SUCCESS(Status)) { FreePool(ReparseData); *Invalid = TRUE; return STATUS_SUCCESS; }
/* Create a string with the substitute name */ SubstituteName.Length = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength; SubstituteName.MaximumLength = SubstituteName.Length; SubstituteName.Buffer = (PWSTR)((ULONG_PTR)ReparseData->SymbolicLinkReparseBuffer.PathBuffer + ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset);
/* If that's a volume name that matches our associated device, that's a success! */ if (MOUNTMGR_IS_VOLUME_NAME(&SubstituteName)) { if (SubstituteName.Length == 98 && SubstituteName.Buffer[1] == L'?') { for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink; SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead); SymlinksEntry = SymlinksEntry->Flink) { SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
if (RtlEqualUnicodeString(&SubstituteName, &SymlinkInformation->Name, TRUE)) { FreePool(ReparseData); return STATUS_SUCCESS; } } } }
FreePool(ReparseData); *Invalid = TRUE; return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSMountMgrQueryVolumePaths(IN PDEVICE_EXTENSION DeviceExtension, IN PDEVICE_INFORMATION DeviceInformation, IN PLIST_ENTRY DeviceInfoList, OUT PMOUNTMGR_VOLUME_PATHS * VolumePaths, OUT PDEVICE_INFORMATION *FailedDevice){ ULONG Written; NTSTATUS Status; PLIST_ENTRY Entry; PSYMLINK_INFORMATION SymlinkInformation; PDEVICE_INFORMATION_ENTRY DeviceInfoEntry; PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry; PMOUNTMGR_VOLUME_PATHS * Paths = NULL, * CurrentPath; ULONG OutputPathLength, NumberOfPaths, ReturnedPaths;
/* We return at least null char */ OutputPathLength = sizeof(UNICODE_NULL);
for (Entry = DeviceInformation->SymbolicLinksListHead.Flink; Entry != &(DeviceInformation->SymbolicLinksListHead); Entry = Entry->Flink) { SymlinkInformation = CONTAINING_RECORD(Entry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
/* Try to find the drive letter (ie, DOS device) */ if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online) { /* We'll return the letter */ OutputPathLength = 4 * sizeof(WCHAR); break; } }
/* We didn't find any */ if (Entry == &(DeviceInformation->SymbolicLinksListHead)) { SymlinkInformation = NULL; }
/* Do we have any device info to return? */ for (Entry = DeviceInfoList->Flink; Entry != DeviceInfoList; Entry = Entry->Flink) { DeviceInfoEntry = CONTAINING_RECORD(Entry, DEVICE_INFORMATION_ENTRY, DeviceInformationEntry);
/* Matching current device */ if (DeviceInfoEntry->DeviceInformation == DeviceInformation) { /* Allocate the output buffer */ *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength); if (*VolumePaths == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
/* Set size */ (*VolumePaths)->MultiSzLength = OutputPathLength; /* If we have a drive letter, return it */ if (SymlinkInformation != NULL) { (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION]; (*VolumePaths)->MultiSz[1] = L':'; (*VolumePaths)->MultiSz[2] = UNICODE_NULL; (*VolumePaths)->MultiSz[3] = UNICODE_NULL; } else { (*VolumePaths)->MultiSz[0] = UNICODE_NULL; }
return STATUS_SUCCESS; } }
/* Allocate a new device entry */ DeviceInfoEntry = AllocatePool(sizeof(DEVICE_INFORMATION_ENTRY)); if (DeviceInfoEntry == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
/* Add it to the list */ DeviceInfoEntry->DeviceInformation = DeviceInformation; InsertTailList(DeviceInfoList, &DeviceInfoEntry->DeviceInformationEntry);
NumberOfPaths = 0; /* Count the amount of devices we will have to handle */ if (!IsListEmpty(&DeviceInformation->AssociatedDevicesHead)) { for (Entry = DeviceInformation->AssociatedDevicesHead.Flink; Entry != &DeviceInformation->AssociatedDevicesHead; Entry = Entry->Flink) { ++NumberOfPaths; }
ASSERT(NumberOfPaths != 0); /* And allocate a big enough buffer */ Paths = AllocatePool(NumberOfPaths * sizeof(PMOUNTMGR_VOLUME_PATHS)); if (Paths == NULL) { RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); FreePool(DeviceInfoEntry); return STATUS_INSUFFICIENT_RESOURCES; } }
/* Start the hot loop to gather all the paths and be able to compute total output length! */ ReturnedPaths = 0; CurrentPath = Paths; for (Entry = DeviceInformation->AssociatedDevicesHead.Flink; Entry != &DeviceInformation->AssociatedDevicesHead; Entry = Entry->Flink) { USHORT InnerStrings; BOOLEAN Invalid = FALSE;
AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
/* Validate the fact its a mount point by query reparse data */ Status = MountMgrValidateBackPointer(AssociatedDeviceEntry, DeviceInformation, &Invalid);
/* If we found an invalid device, that's a failure */ if (Invalid) { *FailedDevice = AssociatedDeviceEntry->DeviceInformation; Status = STATUS_UNSUCCESSFUL; }
/* Check whether we failed, if so, bail out */ if (!NT_SUCCESS(Status)) { ULONG i;
for (i = 0; i < ReturnedPaths; ++i) { FreePool(Paths[i]); }
if (Paths != NULL) { FreePool(Paths); } RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); FreePool(DeviceInfoEntry); return Status; }
/* Query associated paths (hello ourselves :-)) */ Status = MountMgrQueryVolumePaths(DeviceExtension, AssociatedDeviceEntry->DeviceInformation, DeviceInfoList, CurrentPath, FailedDevice); if (!NT_SUCCESS(Status)) { ULONG i;
for (i = 0; i < ReturnedPaths; ++i) { FreePool(Paths[i]); }
if (Paths != NULL) { FreePool(Paths); } RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); FreePool(DeviceInfoEntry); return Status; }
/* Count the number of strings we have in the multi string buffer */ InnerStrings = 0; if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL)) { ULONG i; PWSTR MultiSz = (*CurrentPath)->MultiSz;
for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR); ++i, ++MultiSz) { if (*MultiSz == UNICODE_NULL) { ++InnerStrings; } } }
/* We returned one more path (ie, one more allocated buffer) */ ++ReturnedPaths; /* Move the next pointer to use in the array */ ++CurrentPath; /* Multiply String.Length by the number of found paths, we always add it after a path */ OutputPathLength += (*CurrentPath)->MultiSzLength + InnerStrings * AssociatedDeviceEntry->String.Length - sizeof(UNICODE_NULL); }
/* Allocate the output buffer */ *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength); if (*VolumePaths == NULL) { ULONG i;
for (i = 0; i < ReturnedPaths; ++i) { FreePool(Paths[i]); }
if (Paths != NULL) { FreePool(Paths); } RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); FreePool(DeviceInfoEntry); return STATUS_INSUFFICIENT_RESOURCES; }
Written = 0; /* If we had found a DOS letter, that's the first thing we return */ (*VolumePaths)->MultiSzLength = OutputPathLength; if (SymlinkInformation != NULL) { (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION]; (*VolumePaths)->MultiSz[1] = L':'; (*VolumePaths)->MultiSz[2] = UNICODE_NULL; Written = 3; }
/* Now, browse again all our paths to return them */ CurrentPath = Paths; for (Entry = DeviceInformation->AssociatedDevicesHead.Flink; Entry != &DeviceInformation->AssociatedDevicesHead; Entry = Entry->Flink) { AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
/* If we had a path... */ if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL)) { ULONG i, Offset; PWSTR MultiSz;
/* This offset is used to "jump" into MultiSz, so, start with the string begin (ie, skip MultiSzLength) */ Offset = sizeof(ULONG); /* Browse every single letter, and skip last UNICODE_NULL */ for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR) - 1; ++i) { /* Get the letter */ MultiSz = (PWSTR)((ULONG_PTR)(*CurrentPath) + Offset); /* If it was part of the path, just return it */ if (*MultiSz != UNICODE_NULL) { (*VolumePaths)->MultiSz[Written] = *MultiSz; } else { /* Otherwise, as planed, return our whole associated device name */ RtlCopyMemory(&(*VolumePaths)->MultiSz[Written], AssociatedDeviceEntry->String.Buffer, AssociatedDeviceEntry->String.Length); Written += AssociatedDeviceEntry->String.Length / sizeof(WCHAR); /* And don't forget to nullify */ (*VolumePaths)->MultiSz[Written] = UNICODE_NULL; }
/* We at least return a letter or a null char */ ++Written; /* Move to the next letter */ Offset += sizeof(WCHAR); } }
FreePool(*CurrentPath); ++CurrentPath; }
/* MultiSz: don't forget last null char */ (*VolumePaths)->MultiSz[Written] = UNICODE_NULL; /* Cleanup everything and return success! */ if (Paths != NULL) { FreePool(Paths); } RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry); FreePool(DeviceInfoEntry); return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSMountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ NTSTATUS Status; PLIST_ENTRY Entry; LIST_ENTRY Devices; BOOLEAN NeedNotification; PIO_STACK_LOCATION Stack; UNICODE_STRING SymbolicName; ULONG Attempts, OutputLength; PMOUNTMGR_TARGET_NAME Target; PMOUNTMGR_VOLUME_PATHS Paths, Output; RECONCILE_WORK_ITEM_CONTEXT ReconcileContext; PDEVICE_INFORMATION DeviceInformation, ListDeviceInfo, FailedDevice;
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Validate input size */ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) { return STATUS_INVALID_PARAMETER; }
/* Ensure we have received UNICODE_STRING */ Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; if (Target->DeviceNameLength & 1) { return STATUS_INVALID_PARAMETER; }
/* Validate the entry structure size */ if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength > Stack->Parameters.DeviceIoControl.InputBufferLength) { return STATUS_INVALID_PARAMETER; }
/* Ensure we can at least return needed size */ if (Stack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz)) { return STATUS_INVALID_PARAMETER; }
/* Construct string for query */ SymbolicName.Length = SymbolicName.MaximumLength = Target->DeviceNameLength; SymbolicName.Buffer = Target->DeviceName;
/* Find device with our info */ Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation); if (!NT_SUCCESS(Status)) { return Status; }
NeedNotification = FALSE; Attempts = 0; for (;;) { FailedDevice = NULL; InitializeListHead(&Devices);
/* Query paths */ Status = MountMgrQueryVolumePaths(DeviceExtension, DeviceInformation, &Devices, &Paths, &FailedDevice); if (NT_SUCCESS(Status)) { break; }
/* If it failed for generic reason (memory, whatever), bail out (ie, FailedDevice not set) */ if (FailedDevice == NULL) { return Status; }
/* If PnP, let's notify in case of success */ if (!DeviceInformation->ManuallyRegistered) { NeedNotification = TRUE; }
/* Reconcile database */ ReconcileContext.DeviceExtension = DeviceExtension; ReconcileContext.DeviceInformation = FailedDevice; KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE); ReconcileThisDatabaseWithMasterWorker(&ReconcileContext); KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
/* Look for our device, to check it's online */ for (Entry = DeviceExtension->DeviceListHead.Flink; Entry != &DeviceExtension->DeviceListHead; Entry = Entry->Flink) { ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry); /* It's online, it's OK! */ if (ListDeviceInfo == DeviceInformation) { break; } }
/* It's not online, it's not good */ if (Entry == &DeviceExtension->DeviceListHead) { return STATUS_OBJECT_NAME_NOT_FOUND; }
/* Increase attempts count */ ++Attempts; /* Don't look forever and fail if we get out of attempts */ if (Attempts >= 1000) { return Status; } }
/* We need to notify? Go ahead */ if (NeedNotification) { MountMgrNotifyNameChange(DeviceExtension, &SymbolicName, FALSE); }
/* Get the output buffer */ Output = (PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer;
/* Set required size */ Output->MultiSzLength = Paths->MultiSzLength;
/* Compute total length */ OutputLength = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz) + Output->MultiSzLength;
/* If it cannot fit, just return the size needed and leave */ if (OutputLength > Stack->Parameters.DeviceIoControl.OutputBufferLength) { Irp->IoStatus.Information = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz); FreePool(Paths); return STATUS_BUFFER_OVERFLOW; }
/* Copy data and quit */ Irp->IoStatus.Information = OutputLength; RtlCopyMemory(Output->MultiSz, Paths->MultiSz, Output->MultiSzLength); FreePool(Paths); return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSMountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ NTSTATUS Status; PIO_STACK_LOCATION Stack; UNICODE_STRING SymbolicName; PMOUNTMGR_TARGET_NAME Target; PDEVICE_INFORMATION DeviceInformation;
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Validate input */ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) { return STATUS_INVALID_PARAMETER; }
Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength > Stack->Parameters.DeviceIoControl.InputBufferLength) { return STATUS_INVALID_PARAMETER; }
SymbolicName.Length = SymbolicName.MaximumLength = Target->DeviceNameLength; SymbolicName.Buffer = Target->DeviceName;
/* Find the associated device */ Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation); if (!NT_SUCCESS(Status)) { return Status; }
/* Mark we want to keep links */ DeviceInformation->KeepLinks = TRUE;
return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSMountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ NTSTATUS Status; BOOLEAN OldState; PIO_STACK_LOCATION Stack; UNICODE_STRING SymbolicName; PMOUNTMGR_TARGET_NAME Target;
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Validate input */ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME)) { return STATUS_INVALID_PARAMETER; }
Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer; if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength > Stack->Parameters.DeviceIoControl.InputBufferLength) { return STATUS_INVALID_PARAMETER; }
SymbolicName.Length = SymbolicName.MaximumLength = Target->DeviceNameLength; SymbolicName.Buffer = Target->DeviceName;
/* Disable hard errors */ OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread()); PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
/* Call real worker */ Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE);
PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
return Status;}
/* * @implemented */NTSTATUSMountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ NTSTATUS Status; PIO_STACK_LOCATION Stack; PMOUNTDEV_UNIQUE_ID UniqueId; PMOUNTMGR_MOUNT_POINT MountPoint; UNICODE_STRING SymbolicName, DeviceName;
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Validate input... */ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT)) { return STATUS_INVALID_PARAMETER; }
MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer; if (!MountPoint->SymbolicLinkNameLength) { MountPoint->SymbolicLinkNameOffset = 0; }
if (!MountPoint->UniqueIdLength) { MountPoint->UniqueIdOffset = 0; }
if (!MountPoint->DeviceNameLength) { MountPoint->DeviceNameOffset = 0; }
/* Addresses can't be odd */ if ((MountPoint->SymbolicLinkNameOffset & 1) || (MountPoint->SymbolicLinkNameLength & 1)) { return STATUS_INVALID_PARAMETER; }
if ((MountPoint->UniqueIdOffset & 1) || (MountPoint->UniqueIdLength & 1)) { return STATUS_INVALID_PARAMETER; }
if ((MountPoint->DeviceNameOffset & 1) || (MountPoint->DeviceNameLength & 1)) { return STATUS_INVALID_PARAMETER; }
/* We can't go beyond */ if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength + MountPoint->DeviceNameLength) > Stack->Parameters.DeviceIoControl.InputBufferLength) { return STATUS_INVALID_PARAMETER; }
if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS)) { return STATUS_INVALID_PARAMETER; }
/* If caller provided a Symlink, use it */ if (MountPoint->SymbolicLinkNameLength != 0) { if (MountPoint->SymbolicLinkNameLength > MAXSHORT) { return STATUS_INVALID_PARAMETER; }
SymbolicName.Length = MountPoint->SymbolicLinkNameLength; SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR); SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength); if (!SymbolicName.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; }
RtlCopyMemory(SymbolicName.Buffer, (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset), SymbolicName.Length); SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
/* Query links using it */ Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp); FreePool(SymbolicName.Buffer); } /* If user provided an unique ID */ else if (MountPoint->UniqueIdLength != 0) { UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); if (!UniqueId) { return STATUS_INSUFFICIENT_RESOURCES; }
UniqueId->UniqueIdLength = MountPoint->UniqueIdLength; RtlCopyMemory(UniqueId->UniqueId, (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset), MountPoint->UniqueIdLength);
/* Query links using it */ Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL); FreePool(UniqueId); } /* If caller provided a device name */ else if (MountPoint->DeviceNameLength != 0) { if (MountPoint->DeviceNameLength > MAXSHORT) { return STATUS_INVALID_PARAMETER; }
DeviceName.Length = MountPoint->DeviceNameLength; DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR); DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength); if (!DeviceName.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; }
RtlCopyMemory(DeviceName.Buffer, (PWSTR)((ULONG_PTR)MountPoint + MountPoint->DeviceNameOffset), DeviceName.Length); DeviceName.Buffer[DeviceName.Length / sizeof(WCHAR)] = UNICODE_NULL;
/* Query links using it */ Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, &DeviceName); FreePool(DeviceName.Buffer); } else { /* Otherwise, query all links */ Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, NULL); }
return Status;}
/* * @implemented */NTSTATUSMountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ ULONG Link; NTSTATUS Status; BOOLEAN CreateNoDrive; PIO_STACK_LOCATION Stack; PMOUNTDEV_UNIQUE_ID UniqueId; PMOUNTMGR_MOUNT_POINT MountPoint; PMOUNTMGR_MOUNT_POINTS MountPoints; UNICODE_STRING SymbolicName, DeviceName;
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Validate input */ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT)) { return STATUS_INVALID_PARAMETER; }
/* Query points */ MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer; CreateNoDrive = (MountPoint->SymbolicLinkNameOffset && MountPoint->SymbolicLinkNameLength);
Status = MountMgrQueryPoints(DeviceExtension, Irp); if (!NT_SUCCESS(Status)) { return Status; }
/* For all the points matching the request */ MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer; for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++) { SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength; SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR); SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength); if (!SymbolicName.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; }
RtlCopyMemory(SymbolicName.Buffer, (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset), SymbolicName.Length); SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
/* Create a no drive entry for the drive letters */ if (CreateNoDrive && IsDriveLetter(&SymbolicName)) { UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); if (UniqueId) { UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength; RtlCopyMemory(UniqueId->UniqueId, (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset), MountPoints->MountPoints[Link].UniqueIdLength);
CreateNoDriveLetterEntry(UniqueId); FreePool(UniqueId); } }
/* If there are no link any more, and no need to create a no drive entry */ if (Link == 0 && !CreateNoDrive) { /* Then, delete everything */ UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength); if (UniqueId) { RtlCopyMemory(UniqueId, (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset), MountPoints->MountPoints[Link].UniqueIdLength);
DeleteNoDriveLetterEntry(UniqueId); FreePool(UniqueId); } }
/* Delete all the information about the mount point */ GlobalDeleteSymbolicLink(&SymbolicName); DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, FALSE); RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer); FreePool(SymbolicName.Buffer);
/* Notify the change */ DeviceName.Length = DeviceName.MaximumLength = MountPoints->MountPoints[Link].DeviceNameLength; DeviceName.Buffer = (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].DeviceNameOffset); MountMgrNotifyNameChange(DeviceExtension, &DeviceName, TRUE); }
MountMgrNotify(DeviceExtension);
return Status;}
/* * @implemented */NTSTATUSMountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp){ ULONG Link; NTSTATUS Status; UNICODE_STRING SymbolicName; PMOUNTDEV_UNIQUE_ID UniqueId; PMOUNTMGR_MOUNT_POINTS MountPoints;
/* Query points */ Status = MountMgrQueryPoints(DeviceExtension, Irp); if (!NT_SUCCESS(Status)) { return Status; }
MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer; if (MountPoints->NumberOfMountPoints == 0) { return Status; }
/* For all the mount points */ for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++) { SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength; SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR); SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength); if (!SymbolicName.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; }
RtlCopyMemory(SymbolicName.Buffer, (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset), SymbolicName.Length); SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
/* If the only mount point is a drive letter, then create a no letter drive entry */ if (MountPoints->NumberOfMountPoints == 1 && IsDriveLetter(&SymbolicName)) { UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); if (UniqueId) { UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength; RtlCopyMemory(UniqueId->UniqueId, (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset), MountPoints->MountPoints[Link].UniqueIdLength);
CreateNoDriveLetterEntry(UniqueId); FreePool(UniqueId); } }
/* Simply delete mount point from DB */ DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, TRUE); RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer); FreePool(SymbolicName.Buffer); }
return Status;}
/* * @implemented */NTSTATUSMountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp, IN NTSTATUS LockStatus, OUT PUNICODE_STRING SourceDeviceName, OUT PUNICODE_STRING SourceSymbolicName, OUT PUNICODE_STRING TargetVolumeName){ HANDLE Handle; NTSTATUS Status; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack; ULONG Length, SavedLength; BOOLEAN FOReferenced = FALSE; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; PDEVICE_INFORMATION DeviceInformation; OBJECT_NAME_INFORMATION ObjectNameInfo; FILE_FS_DEVICE_INFORMATION FsDeviceInfo; PFILE_NAME_INFORMATION FileNameInfo = NULL; PMOUNTMGR_VOLUME_MOUNT_POINT VolumeMountPoint; POBJECT_NAME_INFORMATION ObjectNameInfoPtr = NULL; UNICODE_STRING SourceVolumeName, TargetDeviceName;
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Validate input */ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_VOLUME_MOUNT_POINT)) { return STATUS_INVALID_PARAMETER; }
VolumeMountPoint = (PMOUNTMGR_VOLUME_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
if (((ULONG)VolumeMountPoint->SourceVolumeNameLength + VolumeMountPoint->TargetVolumeNameLength) < Stack->Parameters.DeviceIoControl.InputBufferLength) { return STATUS_INVALID_PARAMETER; }
/* Get source volume name */ SourceVolumeName.Length = SourceVolumeName.MaximumLength = VolumeMountPoint->SourceVolumeNameLength; SourceVolumeName.Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset);
InitializeObjectAttributes(&ObjectAttributes, &SourceVolumeName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
/* Open it */ Status = ZwOpenFile(&Handle, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT); if (!NT_SUCCESS(Status)) { return Status; }
TargetDeviceName.Buffer = NULL;
/* Query its attributes */ Status = ZwQueryVolumeInformationFile(Handle, &IoStatusBlock, &FsDeviceInfo, sizeof(FsDeviceInfo), FileFsDeviceInformation); if (!NT_SUCCESS(Status)) { goto Cleanup; }
/* Mount points can be stored only on storage disks */ if (FsDeviceInfo.DeviceType != FILE_DEVICE_DISK && FsDeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
/* And they can be on local fixed disks only */ if (FsDeviceInfo.Characteristics & (FILE_REMOTE_DEVICE | FILE_REMOVABLE_MEDIA)) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
/* Reference it */ Status = ObReferenceObjectByHandle(Handle, 0, *IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL); if (!NT_SUCCESS(Status)) { goto Cleanup; } FOReferenced = TRUE;
/* Get file name */ FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION)); if (!FileNameInfo) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo, sizeof(FILE_NAME_INFORMATION), FileNameInformation); if (Status == STATUS_BUFFER_OVERFLOW) { /* Now we have real length, use it */ Length = FileNameInfo->FileNameLength; FreePool(FileNameInfo);
FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + Length); if (!FileNameInfo) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
/* Really query file name */ Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo, sizeof(FILE_NAME_INFORMATION) + Length, FileNameInformation); }
if (!NT_SUCCESS(Status)) { goto Cleanup; }
/* Get symbolic name */ ObjectNameInfoPtr = &ObjectNameInfo; SavedLength = sizeof(OBJECT_NAME_INFORMATION); Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, sizeof(OBJECT_NAME_INFORMATION), &Length); if (Status == STATUS_INFO_LENGTH_MISMATCH) { /* Once again, with proper size, it works better */ ObjectNameInfoPtr = AllocatePool(Length); if (!ObjectNameInfoPtr) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
SavedLength = Length; Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, SavedLength, &Length); }
if (!NT_SUCCESS(Status)) { goto Cleanup; }
/* Now, query the device name */ Status = QueryDeviceInformation(&ObjectNameInfoPtr->Name, SourceDeviceName, NULL, NULL, NULL, NULL, NULL, NULL); if (!NT_SUCCESS(Status)) { goto Cleanup; }
/* For target volume name, use input */ TargetVolumeName->Length = TargetVolumeName->MaximumLength = VolumeMountPoint->TargetVolumeNameLength; TargetVolumeName->Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset);
/* Query its device name */ Status = QueryDeviceInformation(TargetVolumeName, &TargetDeviceName, NULL, NULL, NULL, NULL, NULL, NULL); if (!NT_SUCCESS(Status)) { goto Cleanup; }
/* Return symbolic name */ SourceSymbolicName->Length = SourceSymbolicName->MaximumLength = (USHORT)FileNameInfo->FileNameLength; SourceSymbolicName->Buffer = (PWSTR)FileNameInfo; /* memmove allows memory overlap */ RtlMoveMemory(SourceSymbolicName->Buffer, FileNameInfo->FileName, SourceSymbolicName->Length); FileNameInfo = NULL;
/* Notify the change */ MountMgrNotify(DeviceExtension); MountMgrNotifyNameChange(DeviceExtension, &TargetDeviceName, TRUE);
/* If we are locked, sync databases if possible */ if (NT_SUCCESS(LockStatus)) { Status = FindDeviceInfo(DeviceExtension, SourceDeviceName, FALSE, &DeviceInformation); if (NT_SUCCESS(Status)) { ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation); } else { Status = STATUS_PENDING; } }
Cleanup: if (TargetDeviceName.Buffer) { FreePool(TargetDeviceName.Buffer); }
if (ObjectNameInfoPtr && ObjectNameInfoPtr != &ObjectNameInfo) { FreePool(ObjectNameInfoPtr); }
if (FileNameInfo) { FreePool(FileNameInfo); }
if (FOReferenced) { ObDereferenceObject(FileObject); }
return Status;}
/* * @implemented */NTSTATUSMountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp, IN NTSTATUS LockStatus){ LONG Offset; BOOLEAN Found; NTSTATUS Status; HANDLE RemoteDatabase; PMOUNTDEV_UNIQUE_ID UniqueId; PDATABASE_ENTRY DatabaseEntry; PASSOCIATED_DEVICE_ENTRY AssociatedEntry; PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation; UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName;
/* Initialize string */ LinkTarget.Length = 0; LinkTarget.MaximumLength = 0xC8; LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength); if (LinkTarget.Buffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
/* If the mount point was created, then, it changed! * Also use it to query some information */ Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName); /* Pending means DB are under synchronization, bail out */ if (Status == STATUS_PENDING) { FreePool(LinkTarget.Buffer); FreePool(SourceDeviceName.Buffer); FreePool(SourceSymbolicName.Buffer); return STATUS_SUCCESS; } else if (!NT_SUCCESS(Status)) { FreePool(LinkTarget.Buffer); return Status; }
/* Query the device information */ Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); if (!NT_SUCCESS(Status)) { /* If it failed, first try to get volume name */ Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName); if (!NT_SUCCESS(Status)) { /* Then, try to read the symlink */ Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget); if (!NT_SUCCESS(Status)) { FreePool(LinkTarget.Buffer); FreePool(SourceDeviceName.Buffer); FreePool(SourceSymbolicName.Buffer); return Status; } } else { FreePool(VolumeName.Buffer); }
FreePool(SourceDeviceName.Buffer);
SourceDeviceName.Length = LinkTarget.Length; SourceDeviceName.MaximumLength = LinkTarget.MaximumLength; SourceDeviceName.Buffer = LinkTarget.Buffer;
/* Now that we have the correct source, reattempt to query information */ Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); if (!NT_SUCCESS(Status)) { FreePool(SourceDeviceName.Buffer); FreePool(SourceSymbolicName.Buffer); return Status; } }
FreePool(SourceDeviceName.Buffer);
/* Get information about target device */ Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation); if (!NT_SUCCESS(Status)) { FreePool(SourceSymbolicName.Buffer); return Status; }
/* Notify if not disabled */ if (!TargetDeviceInformation->SkipNotifications) { PostOnlineNotification(DeviceExtension, &TargetDeviceInformation->SymbolicName); }
/* Open the remote database */ RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE); if (RemoteDatabase == 0) { FreePool(SourceSymbolicName.Buffer); return STATUS_INSUFFICIENT_RESOURCES; }
/* Browse all the entries */ Offset = 0; Found = FALSE; for (;;) { DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset); if (DatabaseEntry == NULL) { break; }
/* Try to find ourselves */ DbName.MaximumLength = DatabaseEntry->SymbolicNameLength; DbName.Length = DbName.MaximumLength; DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset); if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE)) { /* Reference ourselves and update the entry */ ++DatabaseEntry->EntryReferences; Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry); FreePool(DatabaseEntry); Found = TRUE; break; }
Offset += DatabaseEntry->EntrySize; FreePool(DatabaseEntry); }
/* We couldn't find ourselves, we'll have to add ourselves */ if (!Found) { ULONG EntrySize; PUNIQUE_ID_REPLICATE UniqueIdReplicate;
/* Query the device unique ID */ Status = QueryDeviceInformation(&TargetVolumeName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL); if (!NT_SUCCESS(Status)) { FreePool(SourceSymbolicName.Buffer); CloseRemoteDatabase(RemoteDatabase); return Status; }
/* Allocate a database entry */ EntrySize = UniqueId->UniqueIdLength + TargetVolumeName.Length + sizeof(DATABASE_ENTRY); DatabaseEntry = AllocatePool(EntrySize); if (DatabaseEntry == NULL) { FreePool(UniqueId); FreePool(SourceSymbolicName.Buffer); CloseRemoteDatabase(RemoteDatabase); return STATUS_INSUFFICIENT_RESOURCES; }
/* Fill it in */ DatabaseEntry->EntrySize = EntrySize; DatabaseEntry->EntryReferences = 1; DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY); DatabaseEntry->SymbolicNameLength = TargetVolumeName.Length; DatabaseEntry->UniqueIdOffset = TargetVolumeName.Length + sizeof(DATABASE_ENTRY); DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength; RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + sizeof(DATABASE_ENTRY)), TargetVolumeName.Buffer, DatabaseEntry->SymbolicNameLength); RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
/* And write it down */ Status = AddRemoteDatabaseEntry(RemoteDatabase, DatabaseEntry); FreePool(DatabaseEntry); if (!NT_SUCCESS(Status)) { FreePool(UniqueId); FreePool(SourceSymbolicName.Buffer); CloseRemoteDatabase(RemoteDatabase); return Status; }
/* And now, allocate an Unique ID item */ UniqueIdReplicate = AllocatePool(sizeof(UNIQUE_ID_REPLICATE)); if (UniqueIdReplicate == NULL) { FreePool(UniqueId); FreePool(SourceSymbolicName.Buffer); CloseRemoteDatabase(RemoteDatabase); return Status; }
/* To associate it with the device */ UniqueIdReplicate->UniqueId = UniqueId; InsertTailList(&DeviceInformation->ReplicatedUniqueIdsListHead, &UniqueIdReplicate->ReplicatedUniqueIdsListEntry); }
/* We're done with the remote database */ CloseRemoteDatabase(RemoteDatabase);
/* Check we were find writing the entry */ if (!NT_SUCCESS(Status)) { FreePool(SourceSymbolicName.Buffer); return Status; }
/* This is the end, allocate an associated entry */ AssociatedEntry = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY)); if (AssociatedEntry == NULL) { FreePool(SourceSymbolicName.Buffer); return STATUS_INSUFFICIENT_RESOURCES; }
/* Initialize its source name string */ AssociatedEntry->String.Length = SourceSymbolicName.Length; AssociatedEntry->String.MaximumLength = AssociatedEntry->String.Length + sizeof(UNICODE_NULL); AssociatedEntry->String.Buffer = AllocatePool(AssociatedEntry->String.MaximumLength); if (AssociatedEntry->String.Buffer == NULL) { FreePool(AssociatedEntry); FreePool(SourceSymbolicName.Buffer); return STATUS_INSUFFICIENT_RESOURCES; }
/* Copy data & insert in list */ RtlCopyMemory(AssociatedEntry->String.Buffer, SourceSymbolicName.Buffer, SourceSymbolicName.Length); AssociatedEntry->String.Buffer[SourceSymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL; AssociatedEntry->DeviceInformation = DeviceInformation; InsertTailList(&TargetDeviceInformation->AssociatedDevicesHead, &AssociatedEntry->AssociatedDevicesEntry);
/* We're done! */ FreePool(SourceSymbolicName.Buffer); return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSMountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp, IN NTSTATUS LockStatus){ LONG Offset; NTSTATUS Status; PLIST_ENTRY Entry; HANDLE RemoteDatabase; PDATABASE_ENTRY DatabaseEntry; PUNIQUE_ID_REPLICATE UniqueIdReplicate; PASSOCIATED_DEVICE_ENTRY AssociatedEntry; PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation; UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName;
/* Initialize string */ LinkTarget.Length = 0; LinkTarget.MaximumLength = 0xC8; LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength); if (LinkTarget.Buffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
/* If the mount point was deleted, then, it changed! * Also use it to query some information */ Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName); /* Pending means DB are under synchronization, bail out */ if (Status == STATUS_PENDING) { FreePool(LinkTarget.Buffer); FreePool(SourceDeviceName.Buffer); FreePool(SourceSymbolicName.Buffer); return STATUS_SUCCESS; } else if (!NT_SUCCESS(Status)) { FreePool(LinkTarget.Buffer); return Status; }
/* Query the device information */ Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); if (!NT_SUCCESS(Status)) { /* If it failed, first try to get volume name */ Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName); if (!NT_SUCCESS(Status)) { /* Then, try to read the symlink */ Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget); if (!NT_SUCCESS(Status)) { FreePool(LinkTarget.Buffer); FreePool(SourceDeviceName.Buffer); FreePool(SourceSymbolicName.Buffer); return Status; } } else { FreePool(VolumeName.Buffer); }
FreePool(SourceDeviceName.Buffer);
SourceDeviceName.Length = LinkTarget.Length; SourceDeviceName.MaximumLength = LinkTarget.MaximumLength; SourceDeviceName.Buffer = LinkTarget.Buffer;
/* Now that we have the correct source, reattempt to query information */ Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); if (!NT_SUCCESS(Status)) { FreePool(SourceDeviceName.Buffer); FreePool(SourceSymbolicName.Buffer); return Status; } }
FreePool(SourceDeviceName.Buffer);
/* Get information about target device */ Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation); if (!NT_SUCCESS(Status)) { FreePool(SourceSymbolicName.Buffer); return Status; }
/* Open the remote database */ RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE); if (RemoteDatabase == 0) { FreePool(SourceSymbolicName.Buffer); return STATUS_INSUFFICIENT_RESOURCES; }
/* Browse all the entries */ Offset = 0; for (;;) { DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset); if (DatabaseEntry == NULL) { /* We didn't find ourselves, that's infortunate! */ FreePool(SourceSymbolicName.Buffer); CloseRemoteDatabase(RemoteDatabase); return STATUS_INVALID_PARAMETER; }
/* Try to find ourselves */ DbName.MaximumLength = DatabaseEntry->SymbolicNameLength; DbName.Length = DbName.MaximumLength; DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset); if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE)) { break; }
Offset += DatabaseEntry->EntrySize; FreePool(DatabaseEntry); }
/* Dereference ourselves */ DatabaseEntry->EntryReferences--; if (DatabaseEntry->EntryReferences == 0) { /* If we're still referenced, just update the entry */ Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry); } else { /* Otherwise, delete the entry */ Status = DeleteRemoteDatabaseEntry(RemoteDatabase, Offset); if (!NT_SUCCESS(Status)) { FreePool(DatabaseEntry); FreePool(SourceSymbolicName.Buffer); CloseRemoteDatabase(RemoteDatabase); return Status; }
/* Also, delete our unique ID replicated record */ for (Entry = DeviceInformation->ReplicatedUniqueIdsListHead.Flink; Entry != &DeviceInformation->ReplicatedUniqueIdsListHead; Entry = Entry->Flink) { UniqueIdReplicate = CONTAINING_RECORD(Entry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
if (UniqueIdReplicate->UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength && RtlCompareMemory(UniqueIdReplicate->UniqueId->UniqueId, (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength) { break; } }
/* It has to exist! */ if (Entry == &DeviceInformation->ReplicatedUniqueIdsListHead) { FreePool(DatabaseEntry); FreePool(SourceSymbolicName.Buffer); CloseRemoteDatabase(RemoteDatabase); return STATUS_UNSUCCESSFUL; }
/* Remove it and free it */ RemoveEntryList(&UniqueIdReplicate->ReplicatedUniqueIdsListEntry); FreePool(UniqueIdReplicate->UniqueId); FreePool(UniqueIdReplicate); }
/* We're done with the remote database */ FreePool(DatabaseEntry); CloseRemoteDatabase(RemoteDatabase);
/* Check write operation succeed */ if (!NT_SUCCESS(Status)) { FreePool(SourceSymbolicName.Buffer); return Status; }
/* Try to find our associated device entry */ for (Entry = TargetDeviceInformation->AssociatedDevicesHead.Flink; Entry != &TargetDeviceInformation->AssociatedDevicesHead; Entry = Entry->Flink) { AssociatedEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
/* If found, delete it */ if (AssociatedEntry->DeviceInformation == DeviceInformation && RtlEqualUnicodeString(&AssociatedEntry->String, &SourceSymbolicName, TRUE)) { RemoveEntryList(&AssociatedEntry->AssociatedDevicesEntry); FreePool(AssociatedEntry->String.Buffer); FreePool(AssociatedEntry); break; } }
/* We're done! */ FreePool(SourceSymbolicName.Buffer); return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIMountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ PIO_STACK_LOCATION Stack; NTSTATUS Status, LockStatus; PDEVICE_EXTENSION DeviceExtension;
Stack = IoGetCurrentIrpStackLocation(Irp); DeviceExtension = DeviceObject->DeviceExtension;
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
switch (Stack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_MOUNTMGR_CREATE_POINT: Status = MountMgrCreatePoint(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_DELETE_POINTS: Status = MountMgrDeletePoints(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_QUERY_POINTS: Status = MountMgrQueryPoints(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY: Status = MountMgrDeletePointsDbOnly(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER: Status = MountMgrNextDriveLetter(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS: // NOTE: On Win7+, this is handled during driver re-initialization. DeviceExtension->AutomaticDriveLetter = TRUE; MountMgrAssignDriveLetters(DeviceExtension); ReconcileAllDatabasesWithMaster(DeviceExtension); WaitForOnlinesToComplete(DeviceExtension); Status = STATUS_SUCCESS; break;
case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED: KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension); KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); Status = MountMgrVolumeMountPointCreated(DeviceExtension, Irp, LockStatus); if (NT_SUCCESS(LockStatus)) { ReleaseRemoteDatabaseSemaphore(DeviceExtension); }
break;
case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED: KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension); KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); Status = MountMgrVolumeMountPointDeleted(DeviceExtension, Irp, LockStatus); if (NT_SUCCESS(LockStatus)) { ReleaseRemoteDatabaseSemaphore(DeviceExtension); }
break;
case IOCTL_MOUNTMGR_CHANGE_NOTIFY: Status = MountMgrChangeNotify(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE: Status = MountMgrKeepLinksWhenOffline(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES: Status = MountMgrCheckUnprocessedVolumes(DeviceExtension, Irp); goto Complete;
case IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION: KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); Status = MountMgrVolumeArrivalNotification(DeviceExtension, Irp); goto Complete;
case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH: Status = MountMgrQueryDosVolumePath(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS: Status = MountMgrQueryDosVolumePaths(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_SCRUB_REGISTRY: Status = MountMgrScrubRegistry(DeviceExtension); break;
case IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT: Status = MountMgrQueryAutoMount(DeviceExtension, Irp); break;
case IOCTL_MOUNTMGR_SET_AUTO_MOUNT: Status = MountMgrSetAutoMount(DeviceExtension, Irp); break;
default: Status = STATUS_INVALID_DEVICE_REQUEST; }
KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
if (Status != STATUS_PENDING) { goto Complete; }
return Status;
Complete: Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;}