mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
Cleanup ntlock/unlockfile with proper io semantics..same stuff as previous patches
svn path=/trunk/; revision=15269
This commit is contained in:
parent
6f61a478e8
commit
030580a782
1 changed files with 231 additions and 230 deletions
|
@ -30,18 +30,6 @@ SeSetWorldSecurityDescriptor(SECURITY_INFORMATION SecurityInformation,
|
||||||
|
|
||||||
/* INTERNAL FUNCTIONS ********************************************************/
|
/* INTERNAL FUNCTIONS ********************************************************/
|
||||||
|
|
||||||
static
|
|
||||||
NTSTATUS
|
|
||||||
STDCALL
|
|
||||||
IopLockFileCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
|
|
||||||
IN PIRP Irp,
|
|
||||||
IN PVOID Context)
|
|
||||||
{
|
|
||||||
ExFreePool(Context);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
// FIXME: Should I call IoFreeIrp and return STATUS_MORE_PROCESSING_REQUIRED?
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NAME INTERNAL
|
* NAME INTERNAL
|
||||||
* IopCreateFile
|
* IopCreateFile
|
||||||
|
@ -1751,159 +1739,141 @@ NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
|
||||||
*/
|
*/
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtLockFile(IN HANDLE FileHandle,
|
NtLockFile(IN HANDLE FileHandle,
|
||||||
IN HANDLE EventHandle OPTIONAL,
|
IN HANDLE EventHandle OPTIONAL,
|
||||||
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
||||||
IN PVOID ApcContext OPTIONAL,
|
IN PVOID ApcContext OPTIONAL,
|
||||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
IN PLARGE_INTEGER ByteOffset,
|
IN PLARGE_INTEGER ByteOffset,
|
||||||
IN PLARGE_INTEGER Length,
|
IN PLARGE_INTEGER Length,
|
||||||
IN PULONG Key,
|
IN PULONG Key,
|
||||||
IN BOOLEAN FailImmediatedly,
|
IN BOOLEAN FailImmediately,
|
||||||
IN BOOLEAN ExclusiveLock
|
IN BOOLEAN ExclusiveLock)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
PFILE_OBJECT FileObject = NULL;
|
PFILE_OBJECT FileObject = NULL;
|
||||||
PLARGE_INTEGER LocalLength = NULL;
|
PLARGE_INTEGER LocalLength = NULL;
|
||||||
PKEVENT Event = NULL;
|
PIRP Irp = NULL;
|
||||||
PIRP Irp = NULL;
|
PIO_STACK_LOCATION StackPtr;
|
||||||
PIO_STACK_LOCATION StackPtr;
|
PDEVICE_OBJECT DeviceObject;
|
||||||
PDEVICE_OBJECT DeviceObject;
|
PKEVENT Event = NULL;
|
||||||
KPROCESSOR_MODE PreviousMode;
|
BOOLEAN LocalEvent = FALSE;
|
||||||
NTSTATUS Status;
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
OBJECT_HANDLE_INFORMATION HandleInformation;
|
||||||
|
|
||||||
|
/* FIXME: instead of this, use SEH */
|
||||||
|
if (!Length || !ByteOffset) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
// FIXME: instead of this, use SEH when available?
|
/* Get File Object */
|
||||||
if (!Length || !ByteOffset)
|
Status = ObReferenceObjectByHandle(FileHandle,
|
||||||
{
|
0,
|
||||||
Status = STATUS_INVALID_PARAMETER;
|
IoFileObjectType,
|
||||||
goto fail;
|
PreviousMode,
|
||||||
}
|
(PVOID*)&FileObject,
|
||||||
|
&HandleInformation);
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
PreviousMode = ExGetPreviousMode();
|
/* Must have FILE_READ_DATA | FILE_WRITE_DATA access */
|
||||||
|
if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
|
||||||
Status = ObReferenceObjectByHandle(FileHandle,
|
|
||||||
0,
|
|
||||||
IoFileObjectType,
|
|
||||||
PreviousMode,
|
|
||||||
(PVOID*)&FileObject,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
|
||||||
|
|
||||||
Irp = IoAllocateIrp(DeviceObject->StackSize,
|
|
||||||
FALSE);
|
|
||||||
if (Irp == NULL)
|
|
||||||
{
|
|
||||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EventHandle != NULL && !FailImmediatedly)
|
|
||||||
{
|
|
||||||
Status = ObReferenceObjectByHandle(EventHandle,
|
|
||||||
SYNCHRONIZE,
|
|
||||||
ExEventObjectType,
|
|
||||||
PreviousMode,
|
|
||||||
(PVOID*)&Event,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
{
|
||||||
goto fail;
|
DPRINT1("Invalid access rights\n");
|
||||||
}
|
ObDereferenceObject(FileObject);
|
||||||
}
|
return STATUS_ACCESS_DENIED;
|
||||||
else
|
|
||||||
{
|
|
||||||
Event = &FileObject->Event;
|
|
||||||
KeResetEvent(Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trigger FileObject/Event dereferencing */
|
|
||||||
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
|
||||||
|
|
||||||
Irp->RequestorMode = PreviousMode;
|
|
||||||
Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
|
|
||||||
Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
|
|
||||||
|
|
||||||
Irp->UserEvent = Event;
|
|
||||||
Irp->UserIosb = IoStatusBlock;
|
|
||||||
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|
||||||
|
|
||||||
StackPtr = IoGetNextIrpStackLocation(Irp);
|
|
||||||
StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
|
|
||||||
StackPtr->MinorFunction = IRP_MN_LOCK;
|
|
||||||
StackPtr->FileObject = FileObject;
|
|
||||||
|
|
||||||
if (ExclusiveLock)
|
|
||||||
StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
|
|
||||||
|
|
||||||
if (FailImmediatedly)
|
|
||||||
StackPtr->Flags |= SL_FAIL_IMMEDIATELY;
|
|
||||||
|
|
||||||
LocalLength = ExAllocatePoolWithTag(NonPagedPool,
|
|
||||||
sizeof(LARGE_INTEGER),
|
|
||||||
TAG_LOCK);
|
|
||||||
if (!LocalLength)
|
|
||||||
{
|
|
||||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
*LocalLength = *Length;
|
|
||||||
|
|
||||||
StackPtr->Parameters.LockControl.Length = LocalLength;
|
|
||||||
StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
|
|
||||||
StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
|
|
||||||
|
|
||||||
IoSetCompletionRoutine(Irp,
|
|
||||||
IopLockFileCompletionRoutine,
|
|
||||||
LocalLength,
|
|
||||||
TRUE,
|
|
||||||
TRUE,
|
|
||||||
TRUE);
|
|
||||||
|
|
||||||
/* Can't touch FileObject after IoCallDriver since it might be freed */
|
|
||||||
Status = IofCallDriver(DeviceObject, Irp);
|
|
||||||
if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO))
|
|
||||||
{
|
|
||||||
Status = KeWaitForSingleObject(Event,
|
|
||||||
Executive,
|
|
||||||
PreviousMode,
|
|
||||||
FileObject->Flags & FO_ALERTABLE_IO,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (Status != STATUS_WAIT_0)
|
|
||||||
{
|
|
||||||
DPRINT1("NtLockFile -> KeWaitForSingleObject failed!\n");
|
|
||||||
/*
|
|
||||||
* FIXME: Should do some special processing here if alertable wait
|
|
||||||
* was interupted by user apc or a thread alert (STATUS_ALERTED, STATUS_USER_APC)
|
|
||||||
*/
|
|
||||||
return Status; /* Set status to something else? */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = IoStatusBlock->Status;
|
/* Get Event Object */
|
||||||
}
|
if (EventHandle)
|
||||||
|
{
|
||||||
|
Status = ObReferenceObjectByHandle(EventHandle,
|
||||||
|
EVENT_MODIFY_STATE,
|
||||||
|
ExEventObjectType,
|
||||||
|
PreviousMode,
|
||||||
|
(PVOID *)&Event,
|
||||||
|
NULL);
|
||||||
|
if (Status != STATUS_SUCCESS) return(Status);
|
||||||
|
KeClearEvent(Event);
|
||||||
|
}
|
||||||
|
|
||||||
return Status;
|
/* Check if this is a direct open or not */
|
||||||
|
if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
|
||||||
|
{
|
||||||
|
DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
||||||
|
}
|
||||||
|
|
||||||
fail:;
|
/* Check if we should use Sync IO or not */
|
||||||
if (LocalLength)
|
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
|
||||||
ExFreePool(LocalLength);
|
{
|
||||||
|
/* Use File Object event */
|
||||||
|
KeClearEvent(&FileObject->Event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LocalEvent = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if (Irp)
|
/* Allocate the IRP */
|
||||||
IoFreeIrp(Irp);
|
if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
|
||||||
|
{
|
||||||
|
ObDereferenceObject(FileObject);
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
if (Event)
|
/* Allocate local buffer */
|
||||||
ObDereferenceObject(Event);
|
LocalLength = ExAllocatePoolWithTag(NonPagedPool,
|
||||||
|
sizeof(LARGE_INTEGER),
|
||||||
|
TAG_LOCK);
|
||||||
|
if (!LocalLength)
|
||||||
|
{
|
||||||
|
IoFreeIrp(Irp);
|
||||||
|
ObDereferenceObject(FileObject);
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
*LocalLength = *Length;
|
||||||
|
|
||||||
|
/* Set up the IRP */
|
||||||
|
Irp->RequestorMode = PreviousMode;
|
||||||
|
Irp->UserIosb = IoStatusBlock;
|
||||||
|
Irp->UserEvent = Event;
|
||||||
|
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
||||||
|
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
||||||
|
|
||||||
if (FileObject)
|
/* Set up Stack Data */
|
||||||
ObDereferenceObject(FileObject);
|
StackPtr = IoGetNextIrpStackLocation(Irp);
|
||||||
|
StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
|
||||||
|
StackPtr->MinorFunction = IRP_MN_LOCK;
|
||||||
|
StackPtr->FileObject = FileObject;
|
||||||
|
|
||||||
|
/* Set Parameters */
|
||||||
|
StackPtr->Parameters.LockControl.Length = LocalLength;
|
||||||
|
StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
|
||||||
|
StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
|
||||||
|
|
||||||
return Status;
|
/* Set Flags */
|
||||||
|
if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
|
||||||
|
if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
|
||||||
|
|
||||||
|
/* Call the Driver */
|
||||||
|
FileObject->LockOperation = TRUE;
|
||||||
|
Status = IoCallDriver(DeviceObject, Irp);
|
||||||
|
if (Status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
if (!LocalEvent)
|
||||||
|
{
|
||||||
|
KeWaitForSingleObject(&FileObject->Event,
|
||||||
|
Executive,
|
||||||
|
PreviousMode,
|
||||||
|
FileObject->Flags & FO_ALERTABLE_IO,
|
||||||
|
NULL);
|
||||||
|
Status = FileObject->FinalStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the Status */
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2865,93 +2835,124 @@ NtUnlockFile(IN HANDLE FileHandle,
|
||||||
IN PLARGE_INTEGER Length,
|
IN PLARGE_INTEGER Length,
|
||||||
OUT PULONG Key OPTIONAL)
|
OUT PULONG Key OPTIONAL)
|
||||||
{
|
{
|
||||||
PFILE_OBJECT FileObject = NULL;
|
PFILE_OBJECT FileObject = NULL;
|
||||||
PLARGE_INTEGER LocalLength = NULL;
|
PLARGE_INTEGER LocalLength = NULL;
|
||||||
PIRP Irp = NULL;
|
PIRP Irp = NULL;
|
||||||
PIO_STACK_LOCATION StackPtr;
|
PIO_STACK_LOCATION StackPtr;
|
||||||
PDEVICE_OBJECT DeviceObject;
|
PDEVICE_OBJECT DeviceObject;
|
||||||
KPROCESSOR_MODE PreviousMode;
|
KEVENT Event;
|
||||||
NTSTATUS Status;
|
BOOLEAN LocalEvent = FALSE;
|
||||||
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
OBJECT_HANDLE_INFORMATION HandleInformation;
|
||||||
|
|
||||||
|
/* FIXME: instead of this, use SEH */
|
||||||
|
if (!Length || !ByteOffset) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
// FIXME: instead of this, use SEH when available
|
/* Get File Object */
|
||||||
if (!Length || !ByteOffset)
|
Status = ObReferenceObjectByHandle(FileHandle,
|
||||||
{
|
0,
|
||||||
Status = STATUS_INVALID_PARAMETER;
|
IoFileObjectType,
|
||||||
goto fail;
|
PreviousMode,
|
||||||
}
|
(PVOID*)&FileObject,
|
||||||
|
&HandleInformation);
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
PreviousMode = ExGetPreviousMode();
|
/* Must have FILE_READ_DATA | FILE_WRITE_DATA access */
|
||||||
|
if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
|
||||||
|
{
|
||||||
|
DPRINT1("Invalid access rights\n");
|
||||||
|
ObDereferenceObject(FileObject);
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/* Check if this is a direct open or not */
|
||||||
* BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode
|
if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
|
||||||
* It should ONLY fail if we desire an access that conflict with granted access!
|
{
|
||||||
*/
|
DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
|
||||||
Status = ObReferenceObjectByHandle(FileHandle,
|
}
|
||||||
0, //FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to!
|
else
|
||||||
IoFileObjectType,
|
{
|
||||||
PreviousMode,
|
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
||||||
(PVOID*)&FileObject,
|
}
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
/* Check if we should use Sync IO or not */
|
||||||
|
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
|
||||||
|
{
|
||||||
|
/* Use File Object event */
|
||||||
|
KeClearEvent(&FileObject->Event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Use local event */
|
||||||
|
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
|
||||||
|
LocalEvent = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
Irp = IoAllocateIrp(DeviceObject->StackSize,
|
/* Allocate the IRP */
|
||||||
FALSE);
|
if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
|
||||||
if (Irp == NULL)
|
{
|
||||||
{
|
ObDereferenceObject(FileObject);
|
||||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
goto fail;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Trigger FileObject/Event dereferencing */
|
/* Allocate local buffer */
|
||||||
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
LocalLength = ExAllocatePoolWithTag(NonPagedPool,
|
||||||
Irp->RequestorMode = PreviousMode;
|
sizeof(LARGE_INTEGER),
|
||||||
Irp->UserIosb = IoStatusBlock;
|
TAG_LOCK);
|
||||||
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
if (!LocalLength)
|
||||||
|
{
|
||||||
|
IoFreeIrp(Irp);
|
||||||
|
ObDereferenceObject(FileObject);
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
*LocalLength = *Length;
|
||||||
|
|
||||||
|
/* Set up the IRP */
|
||||||
|
Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
|
||||||
|
Irp->RequestorMode = PreviousMode;
|
||||||
|
Irp->UserIosb = IoStatusBlock;
|
||||||
|
Irp->UserEvent = (LocalEvent) ? &Event : NULL;
|
||||||
|
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
||||||
|
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
||||||
|
|
||||||
StackPtr = IoGetNextIrpStackLocation(Irp);
|
/* Set up Stack Data */
|
||||||
StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
|
StackPtr = IoGetNextIrpStackLocation(Irp);
|
||||||
StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
|
StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
|
||||||
StackPtr->DeviceObject = DeviceObject;
|
StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
|
||||||
StackPtr->FileObject = FileObject;
|
StackPtr->FileObject = FileObject;
|
||||||
|
|
||||||
|
/* Set Parameters */
|
||||||
|
StackPtr->Parameters.LockControl.Length = LocalLength;
|
||||||
|
StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
|
||||||
|
StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
|
||||||
|
|
||||||
LocalLength = ExAllocatePoolWithTag(NonPagedPool,
|
/* Call the Driver */
|
||||||
sizeof(LARGE_INTEGER),
|
Status = IoCallDriver(DeviceObject, Irp);
|
||||||
TAG_LOCK);
|
if (Status == STATUS_PENDING)
|
||||||
if (!LocalLength)
|
{
|
||||||
{
|
if (LocalEvent)
|
||||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
{
|
||||||
goto fail;
|
KeWaitForSingleObject(&Event,
|
||||||
}
|
Executive,
|
||||||
|
PreviousMode,
|
||||||
|
FileObject->Flags & FO_ALERTABLE_IO,
|
||||||
|
NULL);
|
||||||
|
Status = IoStatusBlock->Status;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KeWaitForSingleObject(&FileObject->Event,
|
||||||
|
Executive,
|
||||||
|
PreviousMode,
|
||||||
|
FileObject->Flags & FO_ALERTABLE_IO,
|
||||||
|
NULL);
|
||||||
|
Status = FileObject->FinalStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*LocalLength = *Length;
|
/* Return the Status */
|
||||||
|
return Status;
|
||||||
StackPtr->Parameters.LockControl.Length = LocalLength;
|
|
||||||
StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
|
|
||||||
StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
|
|
||||||
|
|
||||||
/* Allways synchronous */
|
|
||||||
Status = IofCallDriver(DeviceObject, Irp);
|
|
||||||
|
|
||||||
ExFreePool(LocalLength);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
|
|
||||||
fail:;
|
|
||||||
if (LocalLength)
|
|
||||||
ExFreePool(LocalLength);
|
|
||||||
|
|
||||||
if (Irp)
|
|
||||||
IoFreeIrp(Irp);
|
|
||||||
|
|
||||||
if (FileObject)
|
|
||||||
ObDereferenceObject(FileObject);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue