sys: IRP_MJ_CREATE: refactoring to support Overwrite

This commit is contained in:
Bill Zissimopoulos 2016-01-07 19:47:45 -08:00
parent 16895a5b68
commit a382db8b01
4 changed files with 156 additions and 44 deletions

View File

@ -61,7 +61,7 @@ static NTSTATUS FspFsvolCleanup(
UINT64 UserContext2 = (UINT_PTR)FileObject->FsContext2;
FSP_FSCTL_TRANSACT_REQ *Request;
FspFileContextClose(FsvolDeviceObject, FsContext);
FspFileContextClose(FsContext, FileObject);
/* create the user-mode file system request; MustSucceed because IRP_MJ_CLEANUP cannot fail */
FspIopCreateRequestMustSucceed(Irp, FileNameRequired ? &FsContext->FileName : 0, 0, &Request);

View File

@ -14,6 +14,9 @@ static NTSTATUS FspFsvolCreate(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOPREP_DISPATCH FspFsvolCreatePrepare;
FSP_IOCMPL_DISPATCH FspFsvolCreateComplete;
static VOID FspFsvolCreatePostClose(
PDEVICE_OBJECT FsvolDeviceObject, PUNICODE_STRING FileName,
UINT64 UserContext, UINT64 UserContext2, NTSTATUS CloseStatus);
static FSP_IOP_REQUEST_FINI FspFsvolCreateRequestFini;
FSP_DRIVER_DISPATCH FspCreate;
@ -23,6 +26,7 @@ FSP_DRIVER_DISPATCH FspCreate;
#pragma alloc_text(PAGE, FspFsvolCreate)
#pragma alloc_text(PAGE, FspFsvolCreatePrepare)
#pragma alloc_text(PAGE, FspFsvolCreateComplete)
#pragma alloc_text(PAGE, FspFsvolCreatePostClose)
#pragma alloc_text(PAGE, FspFsvolCreateRequestFini)
#pragma alloc_text(PAGE, FspCreate)
#endif
@ -368,10 +372,10 @@ VOID FspFsvolCreateComplete(
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_OBJECT FileObject = IrpSp->FileObject;
SHARE_ACCESS TemporaryShareAccess;
UNICODE_STRING ReparseFileName;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
FSP_FILE_CONTEXT *FsContext = FspIopRequestContext(Request, RequestFsContext);
UNICODE_STRING ReparseFileName;
BOOLEAN DeleteOnClose;
if (FspFsctlTransactCreateKind == Request->Kind)
{
@ -445,15 +449,7 @@ VOID FspFsvolCreateComplete(
FsContext->Header.FileSize.QuadPart = Response->Rsp.Create.Opened.AllocationSize;
FsContext->UserContext = Response->Rsp.Create.Opened.UserContext;
/* open the FsContext */
FspIopRequestContext(Request, RequestFsContext) =
FspFileContextOpen(FsvolDeviceObject, FsContext);
/* set up share access on FileObject; user-mode file system assumed to have done share check */
IoSetShareAccess(Response->Rsp.Create.Opened.GrantedAccess, IrpSp->Parameters.Create.ShareAccess,
FileObject, &TemporaryShareAccess);
/* finish setting up the FileObject */
/* set up the FileObject */
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
FileObject->Vpb = FsvolDeviceExtension->FsvrtDeviceObject->Vpb;
FileObject->SectionObjectPointer = &FsContext->NonPaged->SectionObjectPointers;
@ -461,6 +457,59 @@ VOID FspFsvolCreateComplete(
FileObject->FsContext = FsContext;
FileObject->FsContext2 = (PVOID)(UINT_PTR)Response->Rsp.Create.Opened.UserContext2;
DeleteOnClose = BooleanFlagOn(Request->Req.Create.CreateOptions, FILE_DELETE_ON_CLOSE);
/* open the FsContext */
FsContext = FspFileContextOpen(FsContext, FileObject,
Response->Rsp.Create.Opened.GrantedAccess, IrpSp->Parameters.Create.ShareAccess,
&Result);
FspIopRequestContext(Request, RequestFsContext) = FsContext;
if (0 == FsContext)
{
/* unable to open the FsContext; post a close Create2 request */
FspFsvolCreatePostClose(FsvolDeviceObject,
FsvolDeviceExtension->VolumeParams.FileNameRequired ? &FsContext->FileName : 0,
Response->Rsp.Create.Opened.UserContext,
Response->Rsp.Create.Opened.UserContext2,
Result);
FSP_RETURN();
}
if (FILE_OPENED == Response->IoStatus.Information)
{
/*
* FastFat quote:
* If the user wants write access access to the file make sure there
* is not a process mapping this file as an image. Any attempt to
* delete the file will be stopped in fileinfo.c
*
* If the user wants to delete on close, we must check at this
* point though.
*/
if (FlagOn(Response->Rsp.Create.Opened.GrantedAccess, FILE_WRITE_DATA) ||
DeleteOnClose)
{
if (!MmFlushImageSection(&FsContext->NonPaged->SectionObjectPointers,
MmFlushForWrite))
{
Result = DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION;
FspFsvolCreatePostClose(FsvolDeviceObject,
FsvolDeviceExtension->VolumeParams.FileNameRequired ? &FsContext->FileName : 0,
Response->Rsp.Create.Opened.UserContext,
Response->Rsp.Create.Opened.UserContext2,
Result);
FSP_RETURN();
}
}
/* SUCCESS! */
Irp->IoStatus.Information = (ULONG_PTR)Response->IoStatus.Information;
Result = STATUS_SUCCESS;
}
else
if (FILE_SUPERSEDED == Response->IoStatus.Information ||
FILE_OVERWRITTEN == Response->IoStatus.Information)
{
@ -525,7 +574,7 @@ VOID FspFsvolCreateComplete(
if (!NT_SUCCESS(Response->IoStatus.Status))
{
FspFileContextPgioUnlock(FsContext);
FspFileContextClose(FsvolDeviceObject, FsContext);
FspFileContextClose(FsContext, FileObject);
Irp->IoStatus.Information = 0;
Result = Response->IoStatus.Status;
@ -551,6 +600,39 @@ VOID FspFsvolCreateComplete(
IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName);
}
static VOID FspFsvolCreatePostClose(
PDEVICE_OBJECT FsvolDeviceObject, PUNICODE_STRING FileName,
UINT64 UserContext, UINT64 UserContext2, NTSTATUS CloseStatus)
{
PAGED_CODE();
ASSERT(STATUS_SUCCESS != CloseStatus);
FSP_FSCTL_TRANSACT_REQ *Request;
/* create the user-mode file system request; MustSucceed because we cannot fail */
FspIopCreateRequestMustSucceed(0, FileName, 0, &Request);
/* populate the Create2 request */
Request->Kind = FspFsctlTransactCreate2Kind;
Request->Req.Create2.UserContext = UserContext;
Request->Req.Create2.UserContext2 = UserContext2;
Request->Req.Create2.CloseStatus = CloseStatus;
/*
* Post as a BestEffort work request. This allows us to complete our own IRP
* and return immediately.
*/
FspIopPostWorkRequestBestEffort(FsvolDeviceObject, Request);
/*
* Note that it is still possible for this request to not be delivered,
* if the volume device Ioq is stopped. But such failures are benign
* from our perspective, because they mean that the file system is going
* away and should correctly tear things down.
*/
}
static VOID FspFsvolCreateRequestFini(PVOID Context[3])
{
PAGED_CODE();

View File

@ -517,6 +517,8 @@ typedef struct
/* interlocked access */
LONG RefCount;
LONG OpenCount;
/* locked access */
SHARE_ACCESS ShareAccess;
/* read-only after creation (and insertion in the GenericTable) */
PDEVICE_OBJECT FsvolDeviceObject;
UINT64 UserContext;
@ -527,21 +529,15 @@ typedef struct
NTSTATUS FspFileContextCreate(PDEVICE_OBJECT DeviceObject,
ULONG ExtraSize, FSP_FILE_CONTEXT **PFsContext);
VOID FspFileContextDelete(FSP_FILE_CONTEXT *FsContext);
FSP_FILE_CONTEXT *FspFileContextOpen(PDEVICE_OBJECT FsvolDeviceObject,
FSP_FILE_CONTEXT *FsContext);
VOID FspFileContextClose(PDEVICE_OBJECT FsvolDeviceObject,
FSP_FILE_CONTEXT *FsContext);
FSP_FILE_CONTEXT *FspFileContextOpen(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject,
DWORD GrantedAccess, DWORD ShareAccess, NTSTATUS *PResult);
VOID FspFileContextClose(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject);
static inline
VOID FspFileContextRetain(FSP_FILE_CONTEXT *FsContext)
{
InterlockedIncrement(&FsContext->RefCount);
}
static inline
VOID FspFileContextRetain2(FSP_FILE_CONTEXT *FsContext)
{
InterlockedAdd(&FsContext->RefCount, 2);
}
static inline
VOID FspFileContextRelease(FSP_FILE_CONTEXT *FsContext)
{
LONG RefCount = InterlockedDecrement(&FsContext->RefCount);

View File

@ -73,8 +73,8 @@ VOID FspFileContextDelete(FSP_FILE_CONTEXT *FsContext)
FspFree(FsContext);
}
FSP_FILE_CONTEXT *FspFileContextOpen(PDEVICE_OBJECT FsvolDeviceObject,
FSP_FILE_CONTEXT *FsContext)
FSP_FILE_CONTEXT *FspFileContextOpen(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject,
DWORD GrantedAccess, DWORD ShareAccess, NTSTATUS *PResult)
{
/*
* Attempt to insert our FsContext into the volume device's generic table.
@ -82,6 +82,7 @@ FSP_FILE_CONTEXT *FspFileContextOpen(PDEVICE_OBJECT FsvolDeviceObject,
* FsContext instead.
*/
PDEVICE_OBJECT FsvolDeviceObject = FsContext->FsvolDeviceObject;
FSP_FILE_CONTEXT *OpenedFsContext;
BOOLEAN Inserted;
@ -94,29 +95,58 @@ FSP_FILE_CONTEXT *FspFileContextOpen(PDEVICE_OBJECT FsvolDeviceObject,
if (Inserted)
{
/*
* The new FsContext was inserted into the Context table.
* Retain it. There should be (at least) two references to this FsContext,
* one from our caller and one from the Context table.
* The new FsContext was inserted into the Context table. Set its share access
* and retain and open it. There should be (at least) two references to this
* FsContext, one from our caller and one from the Context table.
*/
ASSERT(OpenedFsContext == FsContext);
IoSetShareAccess(GrantedAccess, ShareAccess, FileObject, &FsContext->ShareAccess);
FspFileContextRetain(OpenedFsContext);
OpenedFsContext->OpenCount++;
}
else
{
/*
* The new FsContext was NOT inserted into the Context table,
* instead a prior FsContext is being opened.
* Release the new FsContext since the caller will no longer reference it,
* and retain the prior FsContext TWICE, once for our caller and once for
* the Context table.
* The new FsContext was NOT inserted into the Context table. Instead we are
* opening a prior FsContext that we found in the table.
*
* First check and update the share access. If successful then retain the
* prior FsContext for our caller and release the original FsContext.
*/
ASSERT(OpenedFsContext != FsContext);
FspFileContextRetain2(OpenedFsContext);
}
/*
* FastFat says to do the following on Vista and above.
*
* Quote:
* Do an extra test for writeable user sections if the user did not allow
* write sharing - this is neccessary since a section may exist with no handles
* open to the file its based against.
*/
NTSTATUS Result = STATUS_SUCCESS;
if (!FlagOn(ShareAccess, FILE_SHARE_WRITE) &&
FlagOn(GrantedAccess,
FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE) &&
MmDoesFileHaveUserWritableReferences(&FsContext->NonPaged->SectionObjectPointers))
Result = STATUS_SHARING_VIOLATION;
InterlockedIncrement(&OpenedFsContext->OpenCount);
/* share access check */
if (NT_SUCCESS(Result))
Result = IoCheckShareAccess(GrantedAccess, ShareAccess, FileObject, &FsContext->ShareAccess, TRUE);
if (NT_SUCCESS(Result))
{
FspFileContextRetain(OpenedFsContext);
OpenedFsContext->OpenCount++;
}
else
{
if (0 != PResult)
*PResult = Result;
OpenedFsContext = 0;
}
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
@ -126,20 +156,24 @@ FSP_FILE_CONTEXT *FspFileContextOpen(PDEVICE_OBJECT FsvolDeviceObject,
return OpenedFsContext;
}
VOID FspFileContextClose(PDEVICE_OBJECT FsvolDeviceObject,
FSP_FILE_CONTEXT *FsContext)
VOID FspFileContextClose(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject)
{
/*
* Close the FsContext. If the OpenCount becomes zero remove it
* from the Context table.
*/
if (0 == InterlockedDecrement(&FsContext->OpenCount))
{
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
FspFsvolDeviceDeleteContext(FsvolDeviceObject, FsContext->UserContext, 0);
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
}
PDEVICE_OBJECT FsvolDeviceObject = FsContext->FsvolDeviceObject;
BOOLEAN Deleted = FALSE;
FspFileContextRelease(FsContext);
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
IoRemoveShareAccess(FileObject, &FsContext->ShareAccess);
if (0 == --FsContext->OpenCount)
FspFsvolDeviceDeleteContext(FsvolDeviceObject, FsContext->UserContext, &Deleted);
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (Deleted)
FspFileContextRelease(FsContext);
}