895 lines
22 KiB
C
895 lines
22 KiB
C
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spdriver.c
|
|
|
|
Abstract:
|
|
|
|
Device-driver interface routines for text setup.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 11-August-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
#include "spcmdcon.h"
|
|
|
|
|
|
PSETUP_COMMUNICATION CommunicationParams;
|
|
|
|
PVOID RequestReadyEventObjectBody;
|
|
PVOID RequestReadyEventWaitObjectBody;
|
|
|
|
PVOID RequestServicedEventObjectBody;
|
|
PVOID RequestServicedEventWaitObjectBody;
|
|
|
|
PEPROCESS UsetupProcess;
|
|
PAUTOCHK_MSG_PROCESSING_ROUTINE pAutochkCallbackRoutine;
|
|
|
|
|
|
SYSTEM_BASIC_INFORMATION SystemBasicInfo;
|
|
|
|
BOOLEAN AutochkRunning = FALSE;
|
|
BOOLEAN AutofrmtRunning = FALSE;
|
|
|
|
NTSTATUS
|
|
SetupOpenCreate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SetupClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SetupDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
SetupUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
NTSTATUS
|
|
SpInitialize0(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
BOOLEAN
|
|
pSpVerifyEventWaitable(
|
|
IN HANDLE hEvent,
|
|
OUT PVOID *EventObjectBody,
|
|
OUT PVOID *EventWaitObjectBody
|
|
);
|
|
|
|
ULONG
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the setup driver.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object created by system.
|
|
|
|
RegistryPath - Pointer to the Unicode name of the registry path
|
|
for this driver.
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status from the initialization operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING unicodeString;
|
|
PDEVICE_OBJECT deviceObject;
|
|
|
|
//
|
|
// Create exclusive device object.
|
|
//
|
|
|
|
RtlInitUnicodeString(&unicodeString,DD_SETUP_DEVICE_NAME_U);
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject,
|
|
0,
|
|
&unicodeString,
|
|
FILE_DEVICE_UNKNOWN,
|
|
0,
|
|
FALSE,
|
|
&deviceObject
|
|
);
|
|
|
|
if(!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to create device object (%lx)\n",status));
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Set up device driver entry points.
|
|
//
|
|
//DriverObject->DriverStartIo = NULL;
|
|
DriverObject->DriverUnload = SetupUnload;
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = SetupOpenCreate;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SetupClose;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SetupDeviceControl;
|
|
//DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NULL;
|
|
|
|
return((ULONG)SpInitialize0(DriverObject));
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SetupUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the setup driver unload routine.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Delete the device object.
|
|
//
|
|
|
|
IoDeleteDevice(DriverObject->DeviceObject);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SetupOpenCreate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the dispatch routine for open/create.
|
|
When the setup device is opened, text setup begins.
|
|
The open/create does not complete until text setup is done.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to class device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = FILE_OPENED;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SetupClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the dispatch routine for close.
|
|
Close requests are completed here.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to class device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Complete the request and return status.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SetupDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
NTSTATUS Status;
|
|
PSETUP_START_INFO SetupStartInfo;
|
|
BOOLEAN b;
|
|
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch(IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
case IOCTL_SETUP_START:
|
|
|
|
//
|
|
// Make sure we've been passed a suitable input buffer.
|
|
//
|
|
|
|
if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SETUP_START_INFO)) {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Save away relevent fields in the setup information
|
|
// parameters.
|
|
//
|
|
SetupStartInfo = (PSETUP_START_INFO)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
ResourceImageBase = SetupStartInfo->UserModeImageBase;
|
|
|
|
CommunicationParams = SetupStartInfo->Communication;
|
|
|
|
UsetupProcess = PsGetCurrentProcess();
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: usetup process = %lx \n", UsetupProcess));
|
|
|
|
b = pSpVerifyEventWaitable(
|
|
SetupStartInfo->RequestReadyEvent,
|
|
&RequestReadyEventObjectBody,
|
|
&RequestReadyEventWaitObjectBody
|
|
);
|
|
|
|
if(!b) {
|
|
Status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
b = pSpVerifyEventWaitable(
|
|
SetupStartInfo->RequestServicedEvent,
|
|
&RequestServicedEventObjectBody,
|
|
&RequestServicedEventWaitObjectBody
|
|
);
|
|
|
|
if(!b) {
|
|
Status = STATUS_INVALID_HANDLE;
|
|
ObDereferenceObject(RequestReadyEventObjectBody);
|
|
break;
|
|
}
|
|
|
|
SystemBasicInfo = SetupStartInfo->SystemBasicInfo;
|
|
|
|
//
|
|
// Start Setup going.
|
|
//
|
|
SpStartSetup();
|
|
|
|
ObDereferenceObject(RequestReadyEventObjectBody);
|
|
ObDereferenceObject(RequestServicedEventObjectBody);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case IOCTL_SETUP_FMIFS_MESSAGE:
|
|
|
|
//
|
|
// Make sure that we were not called by usetup.exe.
|
|
// Make sure we've been passed a suitable input buffer.
|
|
//
|
|
if( (UsetupProcess == PsGetCurrentProcess()) ||
|
|
(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SETUP_FMIFS_MESSAGE)) ) {
|
|
|
|
ASSERT( UsetupProcess != PsGetCurrentProcess() );
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
PSETUP_FMIFS_MESSAGE SetupFmifsMessage;
|
|
SetupFmifsMessage = (PSETUP_FMIFS_MESSAGE)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
//
|
|
// If there's a callback override specified, use it.
|
|
//
|
|
if(pAutochkCallbackRoutine) {
|
|
Status = pAutochkCallbackRoutine(SetupFmifsMessage);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If there is a gauge defined, then process the message.
|
|
// Otherwise, don't bother processing it.
|
|
//
|
|
if( UserModeGauge != NULL ) {
|
|
//
|
|
// Save away relevent fields in the setup information
|
|
// parameters.
|
|
//
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: caller process = %lx \n", PsGetCurrentProcess()));
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: FmIfsPacketType = %d \n", SetupFmifsMessage->FmifsPacketType));
|
|
//
|
|
// Find out if the FmIfs packet is one of those that we care about
|
|
//
|
|
if( SetupFmifsMessage->FmifsPacketType == FmIfsPercentCompleted ) {
|
|
ULONG PercentCompleted;
|
|
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: PercentCompleted = %d \n", ((PFMIFS_PERCENT_COMPLETE_INFORMATION)SetupFmifsMessage->FmifsPacket)->PercentCompleted ));
|
|
//
|
|
// Save the percentage in a local variable, before we attach to
|
|
// usetup address space
|
|
//
|
|
PercentCompleted = ((PFMIFS_PERCENT_COMPLETE_INFORMATION)SetupFmifsMessage->FmifsPacket)->PercentCompleted;
|
|
|
|
//
|
|
// We need to adjust the percentage, depending on the partition
|
|
// (System or NT partition) that is currently being accessed.
|
|
// We use this because we want to use only one gauge to display
|
|
// the progress on both System and NT partitions.
|
|
// When autochk is running, 50% of the gauge will be used to
|
|
// display the progress on the system partition, and the remaining
|
|
// 50% will be used for the NT partition.
|
|
// Note that when there are two partitions, the range of the
|
|
// gauge is initialized as 200. When there is only one partition
|
|
// the range is initialized as 100.
|
|
// Note also that when autofmt is running, we always set CurrentDiskIndex
|
|
// to 0.
|
|
//
|
|
ASSERT( CurrentDiskIndex <= 1 );
|
|
PercentCompleted += 100*CurrentDiskIndex;
|
|
|
|
//
|
|
// Attach to usetup.exe address space
|
|
//
|
|
KeAttachProcess( (PKPROCESS)UsetupProcess );
|
|
|
|
//
|
|
// Call the function that processes FmIfsPackets
|
|
//
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Calling ProcessFmIfsPacket \n"));
|
|
// Status = ProcessFmIfsPacket( SetupFmifsMessage );
|
|
|
|
SpFillGauge( UserModeGauge, PercentCompleted );
|
|
|
|
if (AutochkRunning) {
|
|
SendSetupProgressEvent(PartitioningEvent, ValidatePartitionEvent, &PercentCompleted);
|
|
} else if (AutofrmtRunning) {
|
|
SendSetupProgressEvent(PartitioningEvent, FormatPartitionEvent, &PercentCompleted);
|
|
}
|
|
|
|
//
|
|
// Now that the message was processed, detach from usetup.exe
|
|
// address space
|
|
//
|
|
KeDetachProcess();
|
|
} else {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: FmIfsPacketType = %d \n", SetupFmifsMessage->FmifsPacketType));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpSetAutochkCallback(
|
|
IN PAUTOCHK_MSG_PROCESSING_ROUTINE AutochkCallbackRoutine
|
|
)
|
|
{
|
|
pAutochkCallbackRoutine = AutochkCallbackRoutine;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
pSpVerifyEventWaitable(
|
|
IN HANDLE hEvent,
|
|
OUT PVOID *EventObjectBody,
|
|
OUT PVOID *EventWaitObjectBody
|
|
)
|
|
{
|
|
POBJECT_HEADER ObjectHeader;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Reference the event and verify that it is waitable.
|
|
//
|
|
Status = ObReferenceObjectByHandle(
|
|
hEvent,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
KernelMode,
|
|
EventObjectBody,
|
|
NULL
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to reference event object (%lx)\n",Status));
|
|
return(FALSE);
|
|
}
|
|
|
|
ObjectHeader = OBJECT_TO_OBJECT_HEADER(*EventObjectBody);
|
|
if(!ObjectHeader->Type->TypeInfo.UseDefaultObject) {
|
|
|
|
*EventWaitObjectBody = (PVOID)((PCHAR)(*EventObjectBody) +
|
|
(ULONG_PTR)ObjectHeader->Type->DefaultObject);
|
|
|
|
} else {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: event object not waitable!\n"));
|
|
ObDereferenceObject(*EventObjectBody);
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SpInvokeUserModeService(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Set the event indicating that the communication buffer is
|
|
// ready for the user-mode process. Because this is a synchronization
|
|
// event, it automatically resets after releasing the waiting
|
|
// user-mode thread. Note that we specify WaitNext to prevent the
|
|
// race condition between setting this synchronization event and
|
|
// waiting on the next one.
|
|
//
|
|
KeSetEvent(RequestReadyEventObjectBody,EVENT_INCREMENT,TRUE);
|
|
|
|
//
|
|
// Wait for the user-mode process to indicate that it is done
|
|
// processing the request. We wait in user mode so that we can be
|
|
// interrupted if necessary -- say, by an exit APC.
|
|
//
|
|
Status = KeWaitForSingleObject(
|
|
RequestServicedEventWaitObjectBody,
|
|
Executive,
|
|
UserMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: KeWaitForSingleObject returns %lx\n",Status));
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Return the status returned by the user mode process.
|
|
//
|
|
return(CommunicationParams->u.Status);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SpExecuteImage(
|
|
IN PWSTR ImagePath,
|
|
OUT PULONG ReturnStatus, OPTIONAL
|
|
IN ULONG ArgumentCount,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
ULONG i;
|
|
PSERVICE_EXECUTE RequestBuffer;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Locate the request buffer and set up the request number.
|
|
//
|
|
CommunicationParams->u.RequestNumber = SetupServiceExecute;
|
|
RequestBuffer = (PSERVICE_EXECUTE)&CommunicationParams->Buffer;
|
|
|
|
//
|
|
// Determine the lcoations of the two strings that get copied
|
|
// into the request buffer for this service.
|
|
//
|
|
RequestBuffer->FullImagePath = RequestBuffer->Buffer;
|
|
RequestBuffer->CommandLine = RequestBuffer->FullImagePath + wcslen(ImagePath) + 1;
|
|
|
|
//
|
|
// Copy the image path into the request buffer.
|
|
//
|
|
wcscpy(RequestBuffer->FullImagePath,ImagePath);
|
|
|
|
//
|
|
// Move the arguments into the request buffer one by one
|
|
// starting with the image path.
|
|
//
|
|
wcscpy(RequestBuffer->CommandLine,ImagePath);
|
|
va_start(arglist,ArgumentCount);
|
|
for(i=0; i<ArgumentCount; i++) {
|
|
|
|
wcscat(RequestBuffer->CommandLine,L" ");
|
|
wcscat(RequestBuffer->CommandLine,va_arg(arglist,PWSTR));
|
|
}
|
|
va_end(arglist);
|
|
|
|
//
|
|
// Invoke the service.
|
|
//
|
|
Status = SpInvokeUserModeService();
|
|
|
|
//
|
|
// Set process's return status (if required)
|
|
//
|
|
if(NT_SUCCESS(Status) && ReturnStatus) {
|
|
*ReturnStatus = RequestBuffer->ReturnStatus;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpLoadUnloadKey(
|
|
IN HANDLE TargetKeyRootDirectory, OPTIONAL
|
|
IN HANDLE SourceFileRootDirectory, OPTIONAL
|
|
IN PWSTR TargetKeyName,
|
|
IN PWSTR SourceFileName OPTIONAL
|
|
)
|
|
{
|
|
//
|
|
// This was once a user-mode service but now the relevent apis
|
|
// are exported from the kernel so don't bother.
|
|
//
|
|
UNICODE_STRING KeyName,FileName;
|
|
OBJECT_ATTRIBUTES ObjaKey,ObjaFile;
|
|
NTSTATUS Status;
|
|
BOOLEAN Loading;
|
|
BOOLEAN bFileExists = FALSE;
|
|
|
|
//
|
|
// Loading if we have a source filename, otherwise unloading.
|
|
//
|
|
Loading = (BOOLEAN)(SourceFileName != NULL);
|
|
|
|
INIT_OBJA(&ObjaKey,&KeyName,TargetKeyName);
|
|
ObjaKey.RootDirectory = TargetKeyRootDirectory;
|
|
|
|
if(Loading) {
|
|
|
|
INIT_OBJA(&ObjaFile,&FileName,SourceFileName);
|
|
ObjaFile.RootDirectory = SourceFileRootDirectory;
|
|
|
|
//
|
|
// NOTE:ZwLoadKey(...) creates the file if does not exist
|
|
// so we need to check for the existence of the file
|
|
//
|
|
if (SpFileExists(SourceFileName, FALSE))
|
|
Status = ZwLoadKey(&ObjaKey,&ObjaFile);
|
|
else
|
|
Status = STATUS_NO_SUCH_FILE;
|
|
} else {
|
|
Status = ZwUnloadKey(&ObjaKey);
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
|
|
"SETUP: %wskey of %ws failed (%lx)\n",
|
|
Loading ? L"load" : L"unload",
|
|
TargetKeyName,
|
|
Status
|
|
));
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
SpDeleteKey(
|
|
IN HANDLE KeyRootDirectory, OPTIONAL
|
|
IN PWSTR Key
|
|
)
|
|
{
|
|
PSERVICE_DELETE_KEY RequestBuffer;
|
|
|
|
//
|
|
// Locate the request buffer and set up the request number.
|
|
//
|
|
CommunicationParams->u.RequestNumber = SetupServiceDeleteKey;
|
|
|
|
RequestBuffer = (PSERVICE_DELETE_KEY)&CommunicationParams->Buffer;
|
|
|
|
//
|
|
// Determine the lcoation of the strings that get copied
|
|
// into the request buffer for this service.
|
|
//
|
|
RequestBuffer->Key = RequestBuffer->Buffer;
|
|
|
|
//
|
|
// Copy the string into the request buffer.
|
|
//
|
|
wcscpy(RequestBuffer->Buffer,Key);
|
|
|
|
//
|
|
// Initialize the root directory fields.
|
|
//
|
|
RequestBuffer->KeyRootDirectory = KeyRootDirectory;
|
|
|
|
//
|
|
// Invoke the service.
|
|
//
|
|
return(SpInvokeUserModeService());
|
|
}
|
|
|
|
NTSTATUS
|
|
SpQueryDirectoryObject(
|
|
IN HANDLE DirectoryHandle,
|
|
IN BOOLEAN RestartScan,
|
|
IN OUT PULONG Context
|
|
)
|
|
{
|
|
PSERVICE_QUERY_DIRECTORY_OBJECT RequestBuffer;
|
|
NTSTATUS Status;
|
|
|
|
CommunicationParams->u.RequestNumber = SetupServiceQueryDirectoryObject;
|
|
|
|
RequestBuffer = (PSERVICE_QUERY_DIRECTORY_OBJECT)&CommunicationParams->Buffer;
|
|
|
|
RequestBuffer->DirectoryHandle = DirectoryHandle;
|
|
RequestBuffer->Context = *Context;
|
|
RequestBuffer->RestartScan = RestartScan;
|
|
|
|
Status = SpInvokeUserModeService();
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
*Context = RequestBuffer->Context;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpFlushVirtualMemory(
|
|
IN PVOID BaseAddress,
|
|
IN ULONG RangeLength
|
|
)
|
|
{
|
|
PSERVICE_FLUSH_VIRTUAL_MEMORY RequestBuffer;
|
|
|
|
CommunicationParams->u.RequestNumber = SetupServiceFlushVirtualMemory;
|
|
|
|
RequestBuffer = (PSERVICE_FLUSH_VIRTUAL_MEMORY)&CommunicationParams->Buffer;
|
|
|
|
RequestBuffer->BaseAddress = BaseAddress;
|
|
RequestBuffer->RangeLength = RangeLength;
|
|
|
|
return(SpInvokeUserModeService());
|
|
}
|
|
|
|
VOID
|
|
SpShutdownSystem(
|
|
VOID
|
|
)
|
|
{
|
|
SendSetupProgressEvent(SetupCompletedEvent, ShutdownEvent, NULL);
|
|
|
|
CommunicationParams->u.RequestNumber = SetupServiceShutdownSystem;
|
|
|
|
SpInvokeUserModeService();
|
|
|
|
//
|
|
// Shouldn't get here, but just in case...
|
|
//
|
|
HalReturnToFirmware(HalRebootRoutine);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
SpLoadKbdLayoutDll(
|
|
IN PWSTR Directory,
|
|
IN PWSTR DllName,
|
|
OUT PVOID *TableAddress
|
|
)
|
|
{
|
|
PSERVICE_LOAD_KBD_LAYOUT_DLL RequestBuffer;
|
|
NTSTATUS Status;
|
|
|
|
CommunicationParams->u.RequestNumber = SetupServiceLoadKbdLayoutDll;
|
|
|
|
RequestBuffer = (PSERVICE_LOAD_KBD_LAYOUT_DLL)&CommunicationParams->Buffer;
|
|
|
|
wcscpy(RequestBuffer->DllName,Directory);
|
|
SpConcatenatePaths(RequestBuffer->DllName,DllName);
|
|
|
|
Status = SpInvokeUserModeService();
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
*TableAddress = RequestBuffer->TableAddress;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
SpLockUnlockVolume(
|
|
IN HANDLE Handle,
|
|
IN BOOLEAN LockVolume
|
|
)
|
|
{
|
|
PSERVICE_LOCK_UNLOCK_VOLUME RequestBuffer;
|
|
|
|
CommunicationParams->u.RequestNumber = (LockVolume)? SetupServiceLockVolume :
|
|
SetupServiceUnlockVolume;
|
|
|
|
RequestBuffer = (PSERVICE_LOCK_UNLOCK_VOLUME)&CommunicationParams->Buffer;
|
|
|
|
RequestBuffer->Handle = Handle;
|
|
|
|
return(SpInvokeUserModeService());
|
|
}
|
|
|
|
NTSTATUS
|
|
SpDismountVolume(
|
|
IN HANDLE Handle
|
|
)
|
|
{
|
|
PSERVICE_DISMOUNT_VOLUME RequestBuffer;
|
|
|
|
CommunicationParams->u.RequestNumber = SetupServiceDismountVolume;
|
|
|
|
RequestBuffer = (PSERVICE_DISMOUNT_VOLUME)&CommunicationParams->Buffer;
|
|
|
|
RequestBuffer->Handle = Handle;
|
|
|
|
return(SpInvokeUserModeService());
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpSetDefaultFileSecurity(
|
|
IN PWSTR FileName
|
|
)
|
|
{
|
|
PSERVICE_DEFAULT_FILE_SECURITY RequestBuffer;
|
|
|
|
CommunicationParams->u.RequestNumber = SetupServiceSetDefaultFileSecurity;
|
|
|
|
RequestBuffer = (PSERVICE_DEFAULT_FILE_SECURITY)&CommunicationParams->Buffer;
|
|
|
|
wcscpy( RequestBuffer->FileName, FileName );
|
|
|
|
return(SpInvokeUserModeService());
|
|
}
|
|
|
|
NTSTATUS
|
|
SpVerifyFileAccess(
|
|
IN PWSTR FileName,
|
|
IN ACCESS_MASK DesiredAccess
|
|
)
|
|
{
|
|
PSERVICE_VERIFY_FILE_ACCESS RequestBuffer;
|
|
|
|
CommunicationParams->u.RequestNumber = SetupServiceVerifyFileAccess;
|
|
|
|
RequestBuffer = (PSERVICE_VERIFY_FILE_ACCESS)&CommunicationParams->Buffer;
|
|
|
|
wcscpy( RequestBuffer->FileName, FileName );
|
|
RequestBuffer->DesiredAccess = DesiredAccess;
|
|
return(SpInvokeUserModeService());
|
|
}
|
|
|
|
NTSTATUS
|
|
SpCreatePageFile(
|
|
IN PWSTR FileName,
|
|
IN ULONG MinSize,
|
|
IN ULONG MaxSize
|
|
)
|
|
{
|
|
PSERVICE_CREATE_PAGEFILE RequestBuffer;
|
|
|
|
CommunicationParams->u.RequestNumber = SetupServiceCreatePageFile;
|
|
|
|
RequestBuffer = (PSERVICE_CREATE_PAGEFILE)&CommunicationParams->Buffer;
|
|
|
|
wcscpy(RequestBuffer->FileName,FileName);
|
|
RequestBuffer->MinSize.HighPart = 0;
|
|
RequestBuffer->MinSize.LowPart = MinSize;
|
|
RequestBuffer->MaxSize.HighPart = 0;
|
|
RequestBuffer->MaxSize.LowPart = MaxSize;
|
|
|
|
return(SpInvokeUserModeService());
|
|
}
|
|
|
|
NTSTATUS
|
|
SpGetFullPathName(
|
|
IN OUT PWSTR FileName
|
|
)
|
|
{
|
|
PSERVICE_GETFULLPATHNAME RequestBuffer;
|
|
NTSTATUS Status;
|
|
|
|
CommunicationParams->u.RequestNumber = SetupServiceGetFullPathName;
|
|
|
|
RequestBuffer = (PSERVICE_GETFULLPATHNAME)&CommunicationParams->Buffer;
|
|
|
|
wcscpy(RequestBuffer->FileName,FileName);
|
|
|
|
Status = SpInvokeUserModeService();
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
wcscpy(FileName,RequestBuffer->NameOut);
|
|
}
|
|
|
|
return(Status);
|
|
}
|