sys,dll: Cleanup/TruncateOnClose overhaul

This commit is contained in:
Bill Zissimopoulos
2016-12-21 16:09:24 -08:00
parent 8d6314e2db
commit c897ddd864
13 changed files with 203 additions and 69 deletions

View File

@ -875,7 +875,12 @@ FSP_API NTSTATUS FspFileSystemOpCleanup(FSP_FILE_SYSTEM *FileSystem,
FileSystem->Interface->Cleanup(FileSystem,
(PVOID)ValOfFileContext(Request->Req.Cleanup),
0 != Request->FileName.Size ? (PWSTR)Request->Buffer : 0,
0 != Request->Req.Cleanup.Delete);
(0 != Request->Req.Cleanup.Delete ? FspCleanupDelete : 0) |
(0 != Request->Req.Cleanup.SetAllocationSize ? FspCleanupSetAllocationSize : 0) |
(0 != Request->Req.Cleanup.SetArchiveBit ? FspCleanupSetArchiveBit : 0) |
(0 != Request->Req.Cleanup.SetLastAccessTime ? FspCleanupSetLastAccessTime : 0) |
(0 != Request->Req.Cleanup.SetLastWriteTime ? FspCleanupSetLastWriteTime : 0) |
(0 != Request->Req.Cleanup.SetChangeTime ? FspCleanupSetChangeTime : 0));
return STATUS_SUCCESS;
}

View File

@ -523,7 +523,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
opt_data.VolumeParams.PostCleanupOnDeleteOnly = TRUE;
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));

View File

@ -1050,7 +1050,7 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
}
static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PWSTR FileName, BOOLEAN Delete)
PVOID FileNode, PWSTR FileName, ULONG Flags)
{
struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode;
@ -1072,7 +1072,7 @@ static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem,
* FUSE option and can safely remove the file at this time.
*/
if (Delete)
if (Flags & FspCleanupDelete)
if (filedesc->IsDirectory && !filedesc->IsReparsePoint)
{
if (0 != f->ops.rmdir)

View File

@ -77,13 +77,17 @@ static NTSTATUS FspFsvolCleanup(
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FSCTL_TRANSACT_REQ *Request;
BOOLEAN DeletePending;
ULONG CleanupFlags;
BOOLEAN DeletePending, SetAllocationSize, FileModified;
ASSERT(FileNode == FileDesc->FileNode);
FspFileNodeAcquireExclusive(FileNode, Main);
FspFileNodeCleanup(FileNode, FileObject, &DeletePending);
FspFileNodeCleanup(FileNode, FileObject, &CleanupFlags);
DeletePending = CleanupFlags & 1;
SetAllocationSize = !!(CleanupFlags & 2);
FileModified = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
/* if this is a directory inform the FSRTL Notify mechanism */
if (FileNode->IsDirectory)
@ -106,13 +110,23 @@ static NTSTATUS FspFsvolCleanup(
Request->Req.Cleanup.UserContext = FileNode->UserContext;
Request->Req.Cleanup.UserContext2 = FileDesc->UserContext2;
Request->Req.Cleanup.Delete = DeletePending;
Request->Req.Cleanup.SetAllocationSize = SetAllocationSize;
Request->Req.Cleanup.SetArchiveBit = FileModified;
Request->Req.Cleanup.SetLastAccessTime = !FileDesc->DidSetLastAccessTime;
Request->Req.Cleanup.SetLastWriteTime = FileModified && !FileDesc->DidSetLastWriteTime;
Request->Req.Cleanup.SetChangeTime = FileModified;
FspFileNodeAcquireExclusive(FileNode, Pgio);
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp;
if (DeletePending || !FsvolDeviceExtension->VolumeParams.PostCleanupOnDeleteOnly)
if (Request->Req.Cleanup.Delete ||
Request->Req.Cleanup.SetAllocationSize ||
Request->Req.Cleanup.SetArchiveBit ||
Request->Req.Cleanup.SetLastWriteTime ||
Request->Req.Cleanup.SetChangeTime ||
!FsvolDeviceExtension->VolumeParams.PostCleanupWhenModifiedOnly)
/*
* 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

View File

@ -1025,6 +1025,10 @@ NTSTATUS FspFsvolCreateComplete(
if (0 == FileNode->MainFileNode)
FspFileNodeOverwriteStreams(FileNode);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo);
if (0 != Response->Rsp.Overwrite.FileInfo.AllocationSize)
FileNode->TruncateOnClose = TRUE;
FspFileNodeNotifyChange(FileNode,
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED);
@ -1115,9 +1119,14 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
}
if (FILE_CREATED == Response->IoStatus.Information)
{
if (0 != Response->Rsp.Create.Opened.FileInfo.AllocationSize)
FileNode->TruncateOnClose = TRUE;
FspFileNodeNotifyChange(FileNode,
FileNode->IsDirectory ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_ADDED);
}
FspFileNodeRelease(FileNode, Main);

View File

@ -1200,6 +1200,7 @@ typedef struct
BOOLEAN CaseSensitive;
BOOLEAN HasTraversePrivilege;
BOOLEAN DeleteOnClose;
BOOLEAN DidSetLastAccessTime, DidSetLastWriteTime;
BOOLEAN DirectoryHasSuchFile;
UNICODE_STRING DirectoryPattern;
UINT64 DirectoryOffset;
@ -1259,8 +1260,7 @@ VOID FspFileNodeReleaseForeign(FSP_FILE_NODE *FileNode)
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess,
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PBOOLEAN PDeletePending);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags);
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */

View File

@ -34,8 +34,7 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess,
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PBOOLEAN PDeletePending);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags);
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */
@ -635,8 +634,7 @@ exit:
return Result;
}
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PBOOLEAN PDeletePending)
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags)
{
/*
* Determine whether a FileNode should be deleted. Note that when FileNode->DeletePending
@ -650,7 +648,7 @@ VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
BOOLEAN DeletePending, SingleHandle;
BOOLEAN DeletePending, SetAllocationSize, SingleHandle;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
@ -659,12 +657,13 @@ VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
DeletePending = 0 != FileNode->DeletePending;
MemoryBarrier();
SetAllocationSize = !DeletePending && FileNode->TruncateOnClose;
SingleHandle = 1 == FileNode->HandleCount;
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 != PDeletePending)
*PDeletePending = SingleHandle && DeletePending;
*PCleanupFlags = SingleHandle ? DeletePending | (SetAllocationSize << 1) : 0;
}
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject)
@ -684,7 +683,7 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
LARGE_INTEGER TruncateSize = { 0 }, *PTruncateSize = 0;
LARGE_INTEGER TruncateSize, *PTruncateSize = 0;
BOOLEAN DeletePending;
BOOLEAN DeletedFromContextTable = FALSE;
@ -715,23 +714,34 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
if (DeletePending)
{
PTruncateSize = &TruncateSize;
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
&DeletedFromContextTable);
ASSERT(DeletedFromContextTable);
FileNode->OpenCount = 0;
FileNode->Header.FileSize.QuadPart = 0;
}
else if (FileNode->TruncateOnClose && FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
if (DeletePending || FileNode->TruncateOnClose)
{
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FsvolDeviceObject);
UINT64 AllocationUnit =
FsvolDeviceExtension->VolumeParams.SectorSize *
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
/*
* Even when the FileInfo is expired, this is the best guess for a file size
* without asking the user-mode file system.
*/
TruncateSize = FileNode->Header.FileSize;
PTruncateSize = &TruncateSize;
FileNode->Header.AllocationSize.QuadPart = (TruncateSize.QuadPart + AllocationUnit - 1)
/ AllocationUnit * AllocationUnit;
}
FileNode->TruncateOnClose = FALSE;
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);

View File

@ -956,8 +956,11 @@ static NTSTATUS FspFsvolSetBasicInformation(PFILE_OBJECT FileObject,
else
{
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
ULONG NotifyFilter = 0;
ASSERT(FileNode == FileDesc->FileNode);
if (!FileNode->IsDirectory)
{
/* properly set temporary bit for lazy writer */
@ -975,9 +978,15 @@ static NTSTATUS FspFsvolSetBasicInformation(PFILE_OBJECT FileObject,
if (0 != Request->Req.SetInformation.Info.Basic.CreationTime)
NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
if (0 != Request->Req.SetInformation.Info.Basic.LastAccessTime)
{
FileDesc->DidSetLastAccessTime = TRUE;
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
}
if (0 != Request->Req.SetInformation.Info.Basic.LastWriteTime)
{
FileDesc->DidSetLastWriteTime = TRUE;
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
}
FspFileNodeNotifyChange(FileNode, NotifyFilter, FILE_ACTION_MODIFIED);
}

View File

@ -195,6 +195,7 @@ static NTSTATUS FspFsvolWriteCached(
{
ASSERT(CanWait);
/* send EndOfFileInformation IRP; this will also set TruncateOnClose, etc. */
EndOfFileInformation.EndOfFile.QuadPart = WriteEndOffset;
Result = FspSendSetInformationIrp(FsvolDeviceObject/* bypass filters */, FileObject,
FileEndOfFileInformation, &EndOfFileInformation, sizeof EndOfFileInformation);
@ -471,11 +472,14 @@ NTSTATUS FspFsvolWriteComplete(
/* update file info */
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Write.FileInfo);
if (OriginalFileSize != Response->Rsp.Write.FileInfo.FileSize)
if (!PagingIo && OriginalFileSize != Response->Rsp.Write.FileInfo.FileSize)
{
FileNode->TruncateOnClose = TRUE;
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
}
/* update the current file offset if synchronous I/O (and not paging I/O) */
if (SynchronousIo && !PagingIo)
if (!PagingIo && SynchronousIo)
FileObject->CurrentByteOffset.QuadPart = WriteToEndOfFile ?
Response->Rsp.Write.FileInfo.FileSize :
WriteOffset.QuadPart + Response->IoStatus.Information;