mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 08:53:01 -05:00
sys: IRP_MJ_CREATE: refactoring to support Overwrite
This commit is contained in:
parent
16895a5b68
commit
a382db8b01
@ -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);
|
||||
|
106
src/sys/create.c
106
src/sys/create.c
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user