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

@ -146,7 +146,7 @@ typedef struct
UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */ UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */
UINT32 ReadOnlyVolume:1; UINT32 ReadOnlyVolume:1;
/* kernel-mode flags */ /* kernel-mode flags */
UINT32 PostCleanupOnDeleteOnly:1; /* post Cleanup when deleting a file only */ UINT32 PostCleanupWhenModifiedOnly:1; /* post Cleanup when a file was modified/deleted */
UINT32 KmReservedFlags:5; UINT32 KmReservedFlags:5;
/* user-mode flags */ /* user-mode flags */
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */ UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */
@ -248,6 +248,11 @@ typedef struct
UINT64 UserContext; UINT64 UserContext;
UINT64 UserContext2; UINT64 UserContext2;
UINT32 Delete:1; /* file must be deleted */ UINT32 Delete:1; /* file must be deleted */
UINT32 SetAllocationSize:1;
UINT32 SetArchiveBit:1;
UINT32 SetLastAccessTime:1;
UINT32 SetLastWriteTime:1;
UINT32 SetChangeTime:1;
} Cleanup; } Cleanup;
struct struct
{ {

View File

@ -122,6 +122,15 @@ typedef enum
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0, FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE, FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE,
} FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY; } FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY;
enum
{
FspCleanupDelete = 0x01,
FspCleanupSetAllocationSize = 0x02,
FspCleanupSetArchiveBit = 0x10,
FspCleanupSetLastAccessTime = 0x20,
FspCleanupSetLastWriteTime = 0x40,
FspCleanupSetChangeTime = 0x80,
};
/** /**
* @class FSP_FILE_SYSTEM * @class FSP_FILE_SYSTEM
* File system interface. * File system interface.
@ -332,8 +341,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* deleted during Cleanup. * deleted during Cleanup.
* *
* As an optimization a file system may specify the FSP_FSCTL_VOLUME_PARAMS :: * As an optimization a file system may specify the FSP_FSCTL_VOLUME_PARAMS ::
* PostCleanupOnDeleteOnly flag. In this case the FSD will only post Cleanup requests when a * PostCleanupWhenModifiedOnly flag. In this case the FSD will only post Cleanup requests when
* file is being deleted. * the file was modified/deleted.
* *
* @param FileSystem * @param FileSystem
* The file system on which this request is posted. * The file system on which this request is posted.
@ -341,16 +350,17 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* The file context of the file or directory to cleanup. * The file context of the file or directory to cleanup.
* @param FileName * @param FileName
* The name of the file or directory to cleanup. Sent only when a Delete is requested. * The name of the file or directory to cleanup. Sent only when a Delete is requested.
* @param Delete * @param Flags
* Determines whether to delete the file. Note that there is no way to report failure of * These flags determine whether the file was modified and whether to delete the file.
* this operation. Also note that when this parameter is TRUE this is the last outstanding * Note that there is no way to report failure of this operation. Also note that when
* cleanup for this particular file node. * this parameter has the FspCleanupDelete bit set, this is the last outstanding cleanup
* for this particular file node.
* @see * @see
* Close * Close
* CanDelete * CanDelete
*/ */
VOID (*Cleanup)(FSP_FILE_SYSTEM *FileSystem, VOID (*Cleanup)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PWSTR FileName, BOOLEAN Delete); PVOID FileContext, PWSTR FileName, ULONG Flags);
/** /**
* Close a file. * Close a file.
* *

View File

@ -875,7 +875,12 @@ FSP_API NTSTATUS FspFileSystemOpCleanup(FSP_FILE_SYSTEM *FileSystem,
FileSystem->Interface->Cleanup(FileSystem, FileSystem->Interface->Cleanup(FileSystem,
(PVOID)ValOfFileContext(Request->Req.Cleanup), (PVOID)ValOfFileContext(Request->Req.Cleanup),
0 != Request->FileName.Size ? (PWSTR)Request->Buffer : 0, 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; 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.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = FALSE; opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume; opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
opt_data.VolumeParams.PostCleanupOnDeleteOnly = TRUE; opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE; opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0]) if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR)); 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, 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 fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileNode; 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. * FUSE option and can safely remove the file at this time.
*/ */
if (Delete) if (Flags & FspCleanupDelete)
if (filedesc->IsDirectory && !filedesc->IsReparsePoint) if (filedesc->IsDirectory && !filedesc->IsReparsePoint)
{ {
if (0 != f->ops.rmdir) if (0 != f->ops.rmdir)

View File

@ -77,13 +77,17 @@ static NTSTATUS FspFsvolCleanup(
FSP_FILE_NODE *FileNode = FileObject->FsContext; FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2; FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FSCTL_TRANSACT_REQ *Request; FSP_FSCTL_TRANSACT_REQ *Request;
BOOLEAN DeletePending; ULONG CleanupFlags;
BOOLEAN DeletePending, SetAllocationSize, FileModified;
ASSERT(FileNode == FileDesc->FileNode); ASSERT(FileNode == FileDesc->FileNode);
FspFileNodeAcquireExclusive(FileNode, Main); 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 this is a directory inform the FSRTL Notify mechanism */
if (FileNode->IsDirectory) if (FileNode->IsDirectory)
@ -106,13 +110,23 @@ static NTSTATUS FspFsvolCleanup(
Request->Req.Cleanup.UserContext = FileNode->UserContext; Request->Req.Cleanup.UserContext = FileNode->UserContext;
Request->Req.Cleanup.UserContext2 = FileDesc->UserContext2; Request->Req.Cleanup.UserContext2 = FileDesc->UserContext2;
Request->Req.Cleanup.Delete = DeletePending; 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); FspFileNodeAcquireExclusive(FileNode, Pgio);
FspFileNodeSetOwner(FileNode, Full, Request); FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestIrp) = Irp; 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, * 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 * if the volume device Ioq is stopped. But such failures are benign

View File

@ -1025,6 +1025,10 @@ NTSTATUS FspFsvolCreateComplete(
if (0 == FileNode->MainFileNode) if (0 == FileNode->MainFileNode)
FspFileNodeOverwriteStreams(FileNode); FspFileNodeOverwriteStreams(FileNode);
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo); FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Overwrite.FileInfo);
if (0 != Response->Rsp.Overwrite.FileInfo.AllocationSize)
FileNode->TruncateOnClose = TRUE;
FspFileNodeNotifyChange(FileNode, FspFileNodeNotifyChange(FileNode,
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED); 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 (FILE_CREATED == Response->IoStatus.Information)
{
if (0 != Response->Rsp.Create.Opened.FileInfo.AllocationSize)
FileNode->TruncateOnClose = TRUE;
FspFileNodeNotifyChange(FileNode, FspFileNodeNotifyChange(FileNode,
FileNode->IsDirectory ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FileNode->IsDirectory ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_ADDED); FILE_ACTION_ADDED);
}
FspFileNodeRelease(FileNode, Main); FspFileNodeRelease(FileNode, Main);

View File

@ -1200,6 +1200,7 @@ typedef struct
BOOLEAN CaseSensitive; BOOLEAN CaseSensitive;
BOOLEAN HasTraversePrivilege; BOOLEAN HasTraversePrivilege;
BOOLEAN DeleteOnClose; BOOLEAN DeleteOnClose;
BOOLEAN DidSetLastAccessTime, DidSetLastWriteTime;
BOOLEAN DirectoryHasSuchFile; BOOLEAN DirectoryHasSuchFile;
UNICODE_STRING DirectoryPattern; UNICODE_STRING DirectoryPattern;
UINT64 DirectoryOffset; UINT64 DirectoryOffset;
@ -1259,8 +1260,7 @@ VOID FspFileNodeReleaseForeign(FSP_FILE_NODE *FileNode)
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess, UINT32 GrantedAccess, UINT32 ShareAccess,
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason); FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags);
PBOOLEAN PDeletePending);
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject); VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */ 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, NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
UINT32 GrantedAccess, UINT32 ShareAccess, UINT32 GrantedAccess, UINT32 ShareAccess,
FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason); FSP_FILE_NODE **POpenedFileNode, PULONG PSharingViolationReason);
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags);
PBOOLEAN PDeletePending);
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject); VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, VOID FspFileNodeClose(FSP_FILE_NODE *FileNode,
PFILE_OBJECT FileObject, /* non-0 to remove share access */ PFILE_OBJECT FileObject, /* non-0 to remove share access */
@ -635,8 +634,7 @@ exit:
return Result; return Result;
} }
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PULONG PCleanupFlags)
PBOOLEAN PDeletePending)
{ {
/* /*
* Determine whether a FileNode should be deleted. Note that when FileNode->DeletePending * 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; PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2; FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
BOOLEAN DeletePending, SingleHandle; BOOLEAN DeletePending, SetAllocationSize, SingleHandle;
FspFsvolDeviceLockContextTable(FsvolDeviceObject); FspFsvolDeviceLockContextTable(FsvolDeviceObject);
@ -659,12 +657,13 @@ VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
DeletePending = 0 != FileNode->DeletePending; DeletePending = 0 != FileNode->DeletePending;
MemoryBarrier(); MemoryBarrier();
SetAllocationSize = !DeletePending && FileNode->TruncateOnClose;
SingleHandle = 1 == FileNode->HandleCount; SingleHandle = 1 == FileNode->HandleCount;
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 != PDeletePending) *PCleanupFlags = SingleHandle ? DeletePending | (SetAllocationSize << 1) : 0;
*PDeletePending = SingleHandle && DeletePending;
} }
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject) VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject)
@ -684,7 +683,7 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
PAGED_CODE(); PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
LARGE_INTEGER TruncateSize = { 0 }, *PTruncateSize = 0; LARGE_INTEGER TruncateSize, *PTruncateSize = 0;
BOOLEAN DeletePending; BOOLEAN DeletePending;
BOOLEAN DeletedFromContextTable = FALSE; BOOLEAN DeletedFromContextTable = FALSE;
@ -715,23 +714,34 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
if (DeletePending) if (DeletePending)
{ {
PTruncateSize = &TruncateSize;
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName, FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
&DeletedFromContextTable); &DeletedFromContextTable);
ASSERT(DeletedFromContextTable); ASSERT(DeletedFromContextTable);
FileNode->OpenCount = 0; 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 * Even when the FileInfo is expired, this is the best guess for a file size
* without asking the user-mode file system. * without asking the user-mode file system.
*/ */
TruncateSize = FileNode->Header.FileSize; TruncateSize = FileNode->Header.FileSize;
PTruncateSize = &TruncateSize; PTruncateSize = &TruncateSize;
FileNode->Header.AllocationSize.QuadPart = (TruncateSize.QuadPart + AllocationUnit - 1)
/ AllocationUnit * AllocationUnit;
} }
FileNode->TruncateOnClose = FALSE;
} }
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);

View File

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

View File

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

View File

@ -627,9 +627,8 @@ static NTSTATUS GetReparsePointByName(
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize); PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize);
#endif #endif
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS SetFileSizeInternal(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize, PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize);
FSP_FSCTL_FILE_INFO *FileInfo);
static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_VOLUME_INFO *VolumeInfo) FSP_FSCTL_VOLUME_INFO *VolumeInfo)
@ -888,21 +887,6 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
return Result; return Result;
} }
/*
* NTFS and FastFat do this at Cleanup time, but we are going to cheat.
*
* To properly implement this we should maintain some state of whether
* we modified the file or not. Alternatively we could have the driver
* report to us at Cleanup time whether the file was modified. [The
* FSD does maintain the FO_FILE_MODIFIED bit, but does not send it
* to us.]
*
* TBD.
*/
if (0 == (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(GrantedAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
FileNode->FileInfo.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
MemfsFileNodeReference(FileNode); MemfsFileNodeReference(FileNode);
*PFileNode = FileNode; *PFileNode = FileNode;
MemfsFileNodeGetFileInfo(FileNode, FileInfo); MemfsFileNodeGetFileInfo(FileNode, FileInfo);
@ -944,7 +928,7 @@ static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
MemfsFileNodeMapEnumerateFree(&Context); MemfsFileNodeMapEnumerateFree(&Context);
#endif #endif
Result = SetFileSize(FileSystem, FileNode, AllocationSize, TRUE, FileInfo); Result = SetFileSizeInternal(FileSystem, FileNode, AllocationSize, TRUE);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
@ -954,8 +938,9 @@ static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
FileNode->FileInfo.FileAttributes |= FileAttributes | FILE_ATTRIBUTE_ARCHIVE; FileNode->FileInfo.FileAttributes |= FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
FileNode->FileInfo.FileSize = 0; FileNode->FileInfo.FileSize = 0;
FileNode->FileInfo.LastAccessTime =
FileNode->FileInfo.LastWriteTime = FileNode->FileInfo.LastWriteTime =
FileNode->FileInfo.LastAccessTime = MemfsGetSystemTime(); FileNode->FileInfo.ChangeTime = MemfsGetSystemTime();
MemfsFileNodeGetFileInfo(FileNode, FileInfo); MemfsFileNodeGetFileInfo(FileNode, FileInfo);
@ -963,14 +948,41 @@ static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
} }
static VOID Cleanup(FSP_FILE_SYSTEM *FileSystem, static VOID Cleanup(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode0, PWSTR FileName, BOOLEAN Delete) PVOID FileNode0, PWSTR FileName, ULONG Flags)
{ {
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0; MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
assert(Delete); /* the new FSP_FSCTL_VOLUME_PARAMS::PostCleanupOnDeleteOnly ensures this */ assert(0 != Flags); /* FSP_FSCTL_VOLUME_PARAMS::PostCleanupWhenModifiedOnly ensures this */
if (Delete && !MemfsFileNodeMapHasChild(Memfs->FileNodeMap, FileNode)) if (Flags & FspCleanupSetArchiveBit)
{
if (0 == (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
FileNode->FileInfo.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
}
if (Flags & (FspCleanupSetLastAccessTime | FspCleanupSetLastWriteTime | FspCleanupSetChangeTime))
{
UINT64 SystemTime = MemfsGetSystemTime();
if (Flags & FspCleanupSetLastAccessTime)
FileNode->FileInfo.LastAccessTime = SystemTime;
if (Flags & FspCleanupSetLastWriteTime)
FileNode->FileInfo.LastWriteTime = SystemTime;
if (Flags & FspCleanupSetChangeTime)
FileNode->FileInfo.ChangeTime = SystemTime;
}
if (Flags & FspCleanupSetAllocationSize)
{
UINT64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
UINT64 AllocationSize = (FileNode->FileInfo.FileSize + AllocationUnit - 1) /
AllocationUnit * AllocationUnit;
SetFileSizeInternal(FileSystem, FileNode, AllocationSize, TRUE);
}
if ((Flags & FspCleanupDelete) && !MemfsFileNodeMapHasChild(Memfs->FileNodeMap, FileNode))
{ {
#if defined(MEMFS_NAMED_STREAMS) #if defined(MEMFS_NAMED_STREAMS)
MEMFS_FILE_NODE_MAP_ENUM_CONTEXT Context = { FALSE }; MEMFS_FILE_NODE_MAP_ENUM_CONTEXT Context = { FALSE };
@ -1062,7 +1074,7 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
EndOffset = Offset + Length; EndOffset = Offset + Length;
if (EndOffset > FileNode->FileInfo.FileSize) if (EndOffset > FileNode->FileInfo.FileSize)
{ {
Result = SetFileSize(FileSystem, FileNode, EndOffset, FALSE, FileInfo); Result = SetFileSizeInternal(FileSystem, FileNode, EndOffset, FALSE);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
} }
@ -1077,9 +1089,19 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
} }
NTSTATUS Flush(FSP_FILE_SYSTEM *FileSystem, NTSTATUS Flush(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode) PVOID FileNode0)
{ {
/* nothing to do, since we do not cache anything */ MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
/* nothing to flush, since we do not cache anything */
if (0 != FileNode)
{
FileNode->FileInfo.LastAccessTime =
FileNode->FileInfo.LastWriteTime =
FileNode->FileInfo.ChangeTime = MemfsGetSystemTime();
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1120,9 +1142,8 @@ static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS SetFileSizeInternal(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize, PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize)
FSP_FSCTL_FILE_INFO *FileInfo)
{ {
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0; MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
@ -1154,8 +1175,7 @@ static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
UINT64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT; UINT64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
UINT64 AllocationSize = (NewSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit; UINT64 AllocationSize = (NewSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
NTSTATUS Result = SetFileSize(FileSystem, FileNode, AllocationSize, TRUE, NTSTATUS Result = SetFileSizeInternal(FileSystem, FileNode, AllocationSize, TRUE);
FileInfo);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
} }
@ -1167,6 +1187,24 @@ static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
} }
} }
return STATUS_SUCCESS;
}
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo)
{
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
NTSTATUS Result;
Result = SetFileSizeInternal(FileSystem, FileNode0, NewSize, SetAllocationSize);
if (!NT_SUCCESS(Result))
return Result;
FileNode->FileInfo.LastAccessTime =
FileNode->FileInfo.LastWriteTime =
FileNode->FileInfo.ChangeTime = MemfsGetSystemTime();
MemfsFileNodeGetFileInfo(FileNode, FileInfo); MemfsFileNodeGetFileInfo(FileNode, FileInfo);
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -1319,6 +1357,8 @@ static NTSTATUS SetSecurity(FSP_FILE_SYSTEM *FileSystem,
FileNode->FileSecuritySize = FileSecuritySize; FileNode->FileSecuritySize = FileSecuritySize;
FileNode->FileSecurity = FileSecurity; FileNode->FileSecurity = FileSecurity;
FileNode->FileInfo.ChangeTime = MemfsGetSystemTime();
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1523,6 +1563,8 @@ static NTSTATUS SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
FileNode->ReparseData = ReparseData; FileNode->ReparseData = ReparseData;
memcpy(FileNode->ReparseData, Buffer, Size); memcpy(FileNode->ReparseData, Buffer, Size);
FileNode->FileInfo.ChangeTime = MemfsGetSystemTime();
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1556,6 +1598,8 @@ static NTSTATUS DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
FileNode->ReparseDataSize = 0; FileNode->ReparseDataSize = 0;
FileNode->ReparseData = 0; FileNode->ReparseData = 0;
FileNode->FileInfo.ChangeTime = MemfsGetSystemTime();
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
#endif #endif
@ -1737,7 +1781,7 @@ NTSTATUS MemfsCreateFunnel(
#if defined(MEMFS_NAMED_STREAMS) #if defined(MEMFS_NAMED_STREAMS)
VolumeParams.NamedStreams = 1; VolumeParams.NamedStreams = 1;
#endif #endif
VolumeParams.PostCleanupOnDeleteOnly = 1; VolumeParams.PostCleanupWhenModifiedOnly = 1;
if (0 != VolumePrefix) if (0 != VolumePrefix)
wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix); wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR), wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR),

View File

@ -288,9 +288,9 @@ void create_related_test(void)
create_related_dotest(MemfsNet, L"\\\\memfs\\share"); create_related_dotest(MemfsNet, L"\\\\memfs\\share");
} }
void create_allocation_dotest(ULONG Flags, PWSTR Prefix) void create_allocation_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{ {
void *memfs = memfs_start(Flags); void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
HANDLE DirHandle, FileHandle, FileHandle2; HANDLE DirHandle, FileHandle, FileHandle2;
NTSTATUS Result; NTSTATUS Result;
@ -346,10 +346,27 @@ void create_allocation_dotest(ULONG Flags, PWSTR Prefix)
ASSERT(Success); ASSERT(Success);
ASSERT(65536 == StandardInfo.AllocationSize.QuadPart); ASSERT(65536 == StandardInfo.AllocationSize.QuadPart);
CloseHandle(FileHandle2);
AllocationSize.QuadPart = 0;
UnicodePath.Length = (USHORT)wcslen(UnicodePathBuf) * sizeof(WCHAR);
UnicodePath.MaximumLength = sizeof UnicodePathBuf;
UnicodePath.Buffer = UnicodePathBuf;
InitializeObjectAttributes(&Obja, &UnicodePath, 0, DirHandle, 0);
Result = NtCreateFile(&FileHandle2,
FILE_READ_ATTRIBUTES, &Obja, &Iosb,
&AllocationSize, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN, 0, 0, 0);
ASSERT(STATUS_SUCCESS == Result);
Success = GetFileInformationByHandleEx(FileHandle2, FileStandardInfo, &StandardInfo, sizeof StandardInfo);
ASSERT(Success);
ASSERT(65536 == StandardInfo.AllocationSize.QuadPart);
CloseHandle(FileHandle2); CloseHandle(FileHandle2);
CloseHandle(FileHandle); CloseHandle(FileHandle);
#if 0
AllocationSize.QuadPart = 0; AllocationSize.QuadPart = 0;
UnicodePath.Length = (USHORT)wcslen(UnicodePathBuf) * sizeof(WCHAR); UnicodePath.Length = (USHORT)wcslen(UnicodePathBuf) * sizeof(WCHAR);
UnicodePath.MaximumLength = sizeof UnicodePathBuf; UnicodePath.MaximumLength = sizeof UnicodePathBuf;
@ -366,7 +383,6 @@ void create_allocation_dotest(ULONG Flags, PWSTR Prefix)
ASSERT(0 == StandardInfo.AllocationSize.QuadPart); ASSERT(0 == StandardInfo.AllocationSize.QuadPart);
CloseHandle(FileHandle); CloseHandle(FileHandle);
#endif
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2", StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file2",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
@ -388,12 +404,20 @@ void create_allocation_test(void)
{ {
WCHAR DirBuf[MAX_PATH]; WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf); GetTestDirectory(DirBuf);
create_allocation_dotest(-1, DirBuf); create_allocation_dotest(-1, DirBuf, 0);
} }
if (WinFspDiskTests) if (WinFspDiskTests)
create_allocation_dotest(MemfsDisk, 0); {
create_allocation_dotest(MemfsDisk, 0, 0);
create_allocation_dotest(MemfsDisk, 0, 1000);
create_allocation_dotest(MemfsDisk, 0, INFINITE);
}
if (WinFspNetTests) if (WinFspNetTests)
create_allocation_dotest(MemfsNet, L"\\\\memfs\\share"); {
create_allocation_dotest(MemfsNet, L"\\\\memfs\\share", 0);
create_allocation_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
create_allocation_dotest(MemfsNet, L"\\\\memfs\\share", INFINITE);
}
} }
void create_sd_dotest(ULONG Flags, PWSTR Prefix) void create_sd_dotest(ULONG Flags, PWSTR Prefix)