Cleanup ntlock/unlockfile with proper io semantics..same stuff as previous patches

svn path=/trunk/; revision=15269
This commit is contained in:
Alex Ionescu 2005-05-13 21:07:40 +00:00
parent 6f61a478e8
commit 030580a782

View file

@ -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
@ -1759,150 +1747,132 @@ NtLockFile(IN HANDLE FileHandle,
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;
KPROCESSOR_MODE PreviousMode; PKEVENT Event = NULL;
NTSTATUS Status; BOOLEAN LocalEvent = FALSE;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS;
OBJECT_HANDLE_INFORMATION HandleInformation;
// FIXME: instead of this, use SEH when available? /* FIXME: instead of this, use SEH */
if (!Length || !ByteOffset) if (!Length || !ByteOffset) return STATUS_INVALID_PARAMETER;
{
Status = STATUS_INVALID_PARAMETER;
goto fail;
}
PreviousMode = ExGetPreviousMode();
/* Get File Object */
Status = ObReferenceObjectByHandle(FileHandle, Status = ObReferenceObjectByHandle(FileHandle,
0, 0,
IoFileObjectType, IoFileObjectType,
PreviousMode, PreviousMode,
(PVOID*)&FileObject, (PVOID*)&FileObject,
NULL); &HandleInformation);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status)) return Status;
/* Must have FILE_READ_DATA | FILE_WRITE_DATA access */
if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
{ {
goto fail; DPRINT1("Invalid access rights\n");
ObDereferenceObject(FileObject);
return STATUS_ACCESS_DENIED;
} }
DeviceObject = IoGetRelatedDeviceObject(FileObject); /* Get Event Object */
if (EventHandle)
Irp = IoAllocateIrp(DeviceObject->StackSize,
FALSE);
if (Irp == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto fail;
}
if (EventHandle != NULL && !FailImmediatedly)
{ {
Status = ObReferenceObjectByHandle(EventHandle, Status = ObReferenceObjectByHandle(EventHandle,
SYNCHRONIZE, EVENT_MODIFY_STATE,
ExEventObjectType, ExEventObjectType,
PreviousMode, PreviousMode,
(PVOID*)&Event, (PVOID *)&Event,
NULL); NULL);
if (!NT_SUCCESS(Status)) if (Status != STATUS_SUCCESS) return(Status);
{ KeClearEvent(Event);
goto fail;
} }
/* Check if this is a direct open or not */
if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
{
DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
} }
else else
{ {
Event = &FileObject->Event; DeviceObject = IoGetRelatedDeviceObject(FileObject);
KeResetEvent(Event);
} }
/* Trigger FileObject/Event dereferencing */ /* Check if we should use Sync IO or not */
Irp->Tail.Overlay.OriginalFileObject = FileObject; if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Use File Object event */
KeClearEvent(&FileObject->Event);
}
else
{
LocalEvent = TRUE;
}
Irp->RequestorMode = PreviousMode; /* Allocate the IRP */
Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; {
ObDereferenceObject(FileObject);
Irp->UserEvent = Event; return STATUS_INSUFFICIENT_RESOURCES;
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;
/* Allocate local buffer */
LocalLength = ExAllocatePoolWithTag(NonPagedPool, LocalLength = ExAllocatePoolWithTag(NonPagedPool,
sizeof(LARGE_INTEGER), sizeof(LARGE_INTEGER),
TAG_LOCK); TAG_LOCK);
if (!LocalLength) if (!LocalLength)
{ {
Status = STATUS_INSUFFICIENT_RESOURCES; IoFreeIrp(Irp);
goto fail; ObDereferenceObject(FileObject);
return STATUS_INSUFFICIENT_RESOURCES;
} }
*LocalLength = *Length; *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;
/* Set up Stack Data */
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.Length = LocalLength;
StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset; StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
StackPtr->Parameters.LockControl.Key = Key ? *Key : 0; StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
IoSetCompletionRoutine(Irp, /* Set Flags */
IopLockFileCompletionRoutine, if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
LocalLength, if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
TRUE,
TRUE,
TRUE);
/* Can't touch FileObject after IoCallDriver since it might be freed */ /* Call the Driver */
Status = IofCallDriver(DeviceObject, Irp); FileObject->LockOperation = TRUE;
if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO)) Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{ {
Status = KeWaitForSingleObject(Event, if (!LocalEvent)
{
KeWaitForSingleObject(&FileObject->Event,
Executive, Executive,
PreviousMode, PreviousMode,
FileObject->Flags & FO_ALERTABLE_IO, FileObject->Flags & FO_ALERTABLE_IO,
NULL); NULL);
Status = FileObject->FinalStatus;
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; /* Return the Status */
}
return Status;
fail:;
if (LocalLength)
ExFreePool(LocalLength);
if (Irp)
IoFreeIrp(Irp);
if (Event)
ObDereferenceObject(Event);
if (FileObject)
ObDereferenceObject(FileObject);
return Status; return Status;
} }
@ -2870,87 +2840,118 @@ NtUnlockFile(IN HANDLE FileHandle,
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 when available /* FIXME: instead of this, use SEH */
if (!Length || !ByteOffset) if (!Length || !ByteOffset) return STATUS_INVALID_PARAMETER;
{
Status = STATUS_INVALID_PARAMETER;
goto fail;
}
PreviousMode = ExGetPreviousMode(); /* Get File Object */
/*
* BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode
* It should ONLY fail if we desire an access that conflict with granted access!
*/
Status = ObReferenceObjectByHandle(FileHandle, Status = ObReferenceObjectByHandle(FileHandle,
0, //FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to! 0,
IoFileObjectType, IoFileObjectType,
PreviousMode, PreviousMode,
(PVOID*)&FileObject, (PVOID*)&FileObject,
NULL); &HandleInformation);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status)) return Status;
/* Must have FILE_READ_DATA | FILE_WRITE_DATA access */
if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
{ {
goto fail; DPRINT1("Invalid access rights\n");
ObDereferenceObject(FileObject);
return STATUS_ACCESS_DENIED;
} }
/* Check if this is a direct open or not */
if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
{
DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
}
else
{
DeviceObject = IoGetRelatedDeviceObject(FileObject); DeviceObject = IoGetRelatedDeviceObject(FileObject);
Irp = IoAllocateIrp(DeviceObject->StackSize,
FALSE);
if (Irp == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto fail;
} }
/* Trigger FileObject/Event dereferencing */ /* Check if we should use Sync IO or not */
Irp->Tail.Overlay.OriginalFileObject = FileObject; if (FileObject->Flags & FO_SYNCHRONOUS_IO)
Irp->RequestorMode = PreviousMode; {
Irp->UserIosb = IoStatusBlock; /* Use File Object event */
Irp->Tail.Overlay.Thread = PsGetCurrentThread(); KeClearEvent(&FileObject->Event);
}
else
{
/* Use local event */
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
LocalEvent = TRUE;
}
StackPtr = IoGetNextIrpStackLocation(Irp); /* Allocate the IRP */
StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL; if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE; {
StackPtr->DeviceObject = DeviceObject; ObDereferenceObject(FileObject);
StackPtr->FileObject = FileObject; return STATUS_INSUFFICIENT_RESOURCES;
}
/* Allocate local buffer */
LocalLength = ExAllocatePoolWithTag(NonPagedPool, LocalLength = ExAllocatePoolWithTag(NonPagedPool,
sizeof(LARGE_INTEGER), sizeof(LARGE_INTEGER),
TAG_LOCK); TAG_LOCK);
if (!LocalLength) if (!LocalLength)
{ {
Status = STATUS_INSUFFICIENT_RESOURCES; IoFreeIrp(Irp);
goto fail; ObDereferenceObject(FileObject);
return STATUS_INSUFFICIENT_RESOURCES;
} }
*LocalLength = *Length; *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;
/* Set up Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
StackPtr->FileObject = FileObject;
/* Set Parameters */
StackPtr->Parameters.LockControl.Length = LocalLength; StackPtr->Parameters.LockControl.Length = LocalLength;
StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset; StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
StackPtr->Parameters.LockControl.Key = Key ? *Key : 0; StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
/* Allways synchronous */ /* Call the Driver */
Status = IofCallDriver(DeviceObject, Irp); Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
ExFreePool(LocalLength); {
if (LocalEvent)
return Status; {
KeWaitForSingleObject(&Event,
fail:; Executive,
if (LocalLength) PreviousMode,
ExFreePool(LocalLength); FileObject->Flags & FO_ALERTABLE_IO,
NULL);
if (Irp) Status = IoStatusBlock->Status;
IoFreeIrp(Irp); }
else
if (FileObject) {
ObDereferenceObject(FileObject); KeWaitForSingleObject(&FileObject->Event,
Executive,
PreviousMode,
FileObject->Flags & FO_ALERTABLE_IO,
NULL);
Status = FileObject->FinalStatus;
}
}
/* Return the Status */
return Status; return Status;
} }