reactos/drivers/filesystems/reiserfs/src/fileinfo.c

1528 lines
49 KiB
C

/*
* COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
* PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
* FILE: fileinfo.c
* PURPOSE:
* PROGRAMMER: Mark Piper, Matt Wu, Bo Brantén.
* HOMEPAGE:
* UPDATE HISTORY:
*/
/* INCLUDES *****************************************************************/
#include "rfsd.h"
/* GLOBALS ***************************************************************/
extern PRFSD_GLOBAL RfsdGlobal;
/* DEFINITIONS *************************************************************/
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RfsdQueryInformation)
#pragma alloc_text(PAGE, RfsdSetInformation)
#if !RFSD_READ_ONLY
#pragma alloc_text(PAGE, RfsdExpandFile)
#pragma alloc_text(PAGE, RfsdTruncateFile)
#pragma alloc_text(PAGE, RfsdSetDispositionInfo)
#pragma alloc_text(PAGE, RfsdSetRenameInfo)
#pragma alloc_text(PAGE, RfsdDeleteFile)
#endif // !RFSD_READ_ONLY
#endif
__drv_mustHoldCriticalRegion
NTSTATUS
RfsdQueryInformation (IN PRFSD_IRP_CONTEXT IrpContext)
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PFILE_OBJECT FileObject;
PRFSD_VCB Vcb;
PRFSD_FCB Fcb = 0;
PRFSD_CCB Ccb;
PIRP Irp;
PIO_STACK_LOCATION IoStackLocation;
FILE_INFORMATION_CLASS FileInformationClass;
ULONG Length;
PVOID Buffer;
BOOLEAN FcbResourceAcquired = FALSE;
LONGLONG FileSize;
LONGLONG AllocationSize;
PAGED_CODE();
_SEH2_TRY {
ASSERT(IrpContext != NULL);
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
DeviceObject = IrpContext->DeviceObject;
//
// This request is not allowed on the main device object
//
if (DeviceObject == RfsdGlobal->DeviceObject) {
Status = STATUS_INVALID_DEVICE_REQUEST;
_SEH2_LEAVE;
}
FileObject = IrpContext->FileObject;
Fcb = (PRFSD_FCB) FileObject->FsContext;
ASSERT(Fcb != NULL);
//
// This request is not allowed on volumes
//
if (Fcb->Identifier.Type == RFSDVCB) {
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
ASSERT((Fcb->Identifier.Type == RFSDFCB) &&
(Fcb->Identifier.Size == sizeof(RFSD_FCB)));
Vcb = Fcb->Vcb;
/*
if ( !IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY) &&
!FlagOn(Fcb->Flags, FCB_PAGE_FILE))
*/
{
if (!ExAcquireResourceSharedLite(
&Fcb->MainResource,
IrpContext->IsSynchronous
)) {
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
FcbResourceAcquired = TRUE;
}
Ccb = (PRFSD_CCB) FileObject->FsContext2;
ASSERT(Ccb != NULL);
ASSERT((Ccb->Identifier.Type == RFSDCCB) &&
(Ccb->Identifier.Size == sizeof(RFSD_CCB)));
Irp = IrpContext->Irp;
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
FileInformationClass =
IoStackLocation->Parameters.QueryFile.FileInformationClass;
Length = IoStackLocation->Parameters.QueryFile.Length;
Buffer = Irp->AssociatedIrp.SystemBuffer;
RtlZeroMemory(Buffer, Length);
FileSize = (LONGLONG) Fcb->Inode->i_size;
AllocationSize = CEILING_ALIGNED(FileSize, (ULONGLONG)Vcb->BlockSize);
switch (FileInformationClass) {
case FileBasicInformation:
{
PFILE_BASIC_INFORMATION FileBasicInformation;
if (Length < sizeof(FILE_BASIC_INFORMATION)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
FileBasicInformation = (PFILE_BASIC_INFORMATION) Buffer;
FileBasicInformation->CreationTime = RfsdSysTime(Fcb->Inode->i_ctime);
FileBasicInformation->LastAccessTime = RfsdSysTime(Fcb->Inode->i_atime);
FileBasicInformation->LastWriteTime = RfsdSysTime(Fcb->Inode->i_mtime);
FileBasicInformation->ChangeTime = RfsdSysTime(Fcb->Inode->i_mtime);
FileBasicInformation->FileAttributes = Fcb->RfsdMcb->FileAttr;
Irp->IoStatus.Information = sizeof(FILE_BASIC_INFORMATION);
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
#if (_WIN32_WINNT >= 0x0500)
case FileAttributeTagInformation:
{
PFILE_ATTRIBUTE_TAG_INFORMATION FATI;
if (Length < sizeof(FILE_ATTRIBUTE_TAG_INFORMATION)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
FATI = (PFILE_ATTRIBUTE_TAG_INFORMATION) Buffer;
FATI->FileAttributes = Fcb->RfsdMcb->FileAttr;
FATI->ReparseTag = 0;
Irp->IoStatus.Information = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
#endif // (_WIN32_WINNT >= 0x0500)
case FileStandardInformation:
{
PFILE_STANDARD_INFORMATION FileStandardInformation;
if (Length < sizeof(FILE_STANDARD_INFORMATION)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
FileStandardInformation = (PFILE_STANDARD_INFORMATION) Buffer;
FileStandardInformation->AllocationSize.QuadPart = AllocationSize;
FileStandardInformation->EndOfFile.QuadPart = FileSize;
FileStandardInformation->NumberOfLinks = Fcb->Inode->i_links_count;
if (IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY))
FileStandardInformation->DeletePending = FALSE;
else
FileStandardInformation->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING);
if (Fcb->RfsdMcb->FileAttr & FILE_ATTRIBUTE_DIRECTORY) {
FileStandardInformation->Directory = TRUE;
} else {
FileStandardInformation->Directory = FALSE;
}
Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
case FileInternalInformation:
{
PFILE_INTERNAL_INFORMATION FileInternalInformation;
if (Length < sizeof(FILE_INTERNAL_INFORMATION)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
FileInternalInformation = (PFILE_INTERNAL_INFORMATION) Buffer;
// The "inode number"
FileInternalInformation->IndexNumber.LowPart = Fcb->RfsdMcb->Key.k_dir_id;
FileInternalInformation->IndexNumber.HighPart = Fcb->RfsdMcb->Key.k_objectid;
Irp->IoStatus.Information = sizeof(FILE_INTERNAL_INFORMATION);
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
case FileEaInformation:
{
PFILE_EA_INFORMATION FileEaInformation;
if (Length < sizeof(FILE_EA_INFORMATION)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
FileEaInformation = (PFILE_EA_INFORMATION) Buffer;
// Romfs doesn't have any extended attributes
FileEaInformation->EaSize = 0;
Irp->IoStatus.Information = sizeof(FILE_EA_INFORMATION);
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
case FileNameInformation:
{
PFILE_NAME_INFORMATION FileNameInformation;
if (Length < sizeof(FILE_NAME_INFORMATION) +
Fcb->RfsdMcb->ShortName.Length - sizeof(WCHAR)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
FileNameInformation = (PFILE_NAME_INFORMATION) Buffer;
FileNameInformation->FileNameLength = Fcb->RfsdMcb->ShortName.Length;
RtlCopyMemory(
FileNameInformation->FileName,
Fcb->RfsdMcb->ShortName.Buffer,
Fcb->RfsdMcb->ShortName.Length );
Irp->IoStatus.Information = sizeof(FILE_NAME_INFORMATION) +
Fcb->RfsdMcb->ShortName.Length - sizeof(WCHAR);
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
case FilePositionInformation:
{
PFILE_POSITION_INFORMATION FilePositionInformation;
if (Length < sizeof(FILE_POSITION_INFORMATION)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer;
FilePositionInformation->CurrentByteOffset =
FileObject->CurrentByteOffset;
Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
case FileAllInformation:
{
PFILE_ALL_INFORMATION FileAllInformation;
PFILE_BASIC_INFORMATION FileBasicInformation;
PFILE_STANDARD_INFORMATION FileStandardInformation;
PFILE_INTERNAL_INFORMATION FileInternalInformation;
PFILE_EA_INFORMATION FileEaInformation;
PFILE_POSITION_INFORMATION FilePositionInformation;
PFILE_NAME_INFORMATION FileNameInformation;
if (Length < sizeof(FILE_ALL_INFORMATION)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
FileAllInformation = (PFILE_ALL_INFORMATION) Buffer;
FileBasicInformation =
&FileAllInformation->BasicInformation;
FileStandardInformation =
&FileAllInformation->StandardInformation;
FileInternalInformation =
&FileAllInformation->InternalInformation;
FileEaInformation =
&FileAllInformation->EaInformation;
FilePositionInformation =
&FileAllInformation->PositionInformation;
FileNameInformation =
&FileAllInformation->NameInformation;
FileBasicInformation->CreationTime = RfsdSysTime(Fcb->Inode->i_ctime);
FileBasicInformation->LastAccessTime = RfsdSysTime(Fcb->Inode->i_atime);
FileBasicInformation->LastWriteTime = RfsdSysTime(Fcb->Inode->i_mtime);
FileBasicInformation->ChangeTime = RfsdSysTime(Fcb->Inode->i_mtime);
FileBasicInformation->FileAttributes = Fcb->RfsdMcb->FileAttr;
FileStandardInformation->AllocationSize.QuadPart = AllocationSize;
FileStandardInformation->EndOfFile.QuadPart = FileSize;
FileStandardInformation->NumberOfLinks = Fcb->Inode->i_links_count;
if (IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY))
FileStandardInformation->DeletePending = FALSE;
else
FileStandardInformation->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING);
if (FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) {
FileStandardInformation->Directory = TRUE;
} else {
FileStandardInformation->Directory = FALSE;
}
// The "inode number"
FileInternalInformation->IndexNumber.LowPart = Fcb->RfsdMcb->Key.k_dir_id;
FileInternalInformation->IndexNumber.HighPart = Fcb->RfsdMcb->Key.k_objectid;
// Romfs doesn't have any extended attributes
FileEaInformation->EaSize = 0;
FilePositionInformation->CurrentByteOffset =
FileObject->CurrentByteOffset;
if (Length < sizeof(FILE_ALL_INFORMATION) +
Fcb->RfsdMcb->ShortName.Length - sizeof(WCHAR)) {
Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION);
Status = STATUS_BUFFER_OVERFLOW;
_SEH2_LEAVE;
}
FileNameInformation->FileNameLength = Fcb->RfsdMcb->ShortName.Length;
RtlCopyMemory(
FileNameInformation->FileName,
Fcb->RfsdMcb->ShortName.Buffer,
Fcb->RfsdMcb->ShortName.Length
);
Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION) +
Fcb->RfsdMcb->ShortName.Length - sizeof(WCHAR);
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
/*
case FileAlternateNameInformation:
{
// TODO: [ext2fsd] Handle FileAlternateNameInformation
// Here we would like to use RtlGenerate8dot3Name but I don't
// know how to use the argument PGENERATE_NAME_CONTEXT
}
*/
case FileNetworkOpenInformation:
{
PFILE_NETWORK_OPEN_INFORMATION FileNetworkOpenInformation;
if (Length < sizeof(FILE_NETWORK_OPEN_INFORMATION)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
FileNetworkOpenInformation =
(PFILE_NETWORK_OPEN_INFORMATION) Buffer;
FileNetworkOpenInformation->CreationTime = RfsdSysTime(Fcb->Inode->i_ctime);
FileNetworkOpenInformation->LastAccessTime = RfsdSysTime(Fcb->Inode->i_atime);
FileNetworkOpenInformation->LastWriteTime = RfsdSysTime(Fcb->Inode->i_mtime);
FileNetworkOpenInformation->ChangeTime = RfsdSysTime(Fcb->Inode->i_mtime);
FileNetworkOpenInformation->AllocationSize.QuadPart = AllocationSize;
FileNetworkOpenInformation->EndOfFile.QuadPart = FileSize;
FileNetworkOpenInformation->FileAttributes = Fcb->RfsdMcb->FileAttr;
Irp->IoStatus.Information =
sizeof(FILE_NETWORK_OPEN_INFORMATION);
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
default:
Status = STATUS_INVALID_INFO_CLASS;
}
} _SEH2_FINALLY {
if (FcbResourceAcquired) {
ExReleaseResourceForThreadLite(
&Fcb->MainResource,
ExGetCurrentResourceThread());
}
if (!IrpContext->ExceptionInProgress) {
if (Status == STATUS_PENDING) {
RfsdQueueRequest(IrpContext);
} else {
RfsdCompleteIrpContext(IrpContext, Status);
}
}
} _SEH2_END;
return Status;
}
__drv_mustHoldCriticalRegion
NTSTATUS
RfsdSetInformation (IN PRFSD_IRP_CONTEXT IrpContext)
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PRFSD_VCB Vcb = 0;
PFILE_OBJECT FileObject;
PRFSD_FCB Fcb = 0;
PRFSD_CCB Ccb;
PIRP Irp;
PIO_STACK_LOCATION IoStackLocation;
FILE_INFORMATION_CLASS FileInformationClass;
ULONG NotifyFilter = 0;
ULONG Length;
PVOID Buffer;
BOOLEAN FcbMainResourceAcquired = FALSE;
BOOLEAN VcbResourceAcquired = FALSE;
BOOLEAN FcbPagingIoResourceAcquired = FALSE;
PAGED_CODE();
_SEH2_TRY {
ASSERT(IrpContext != NULL);
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
DeviceObject = IrpContext->DeviceObject;
//
// This request is not allowed on the main device object
//
if (DeviceObject == RfsdGlobal->DeviceObject) {
Status = STATUS_INVALID_DEVICE_REQUEST;
_SEH2_LEAVE;
}
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
ASSERT(Vcb != NULL);
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
ASSERT(IsMounted(Vcb));
FileObject = IrpContext->FileObject;
Fcb = (PRFSD_FCB) FileObject->FsContext;
ASSERT(Fcb != NULL);
//
// This request is not allowed on volumes
//
if (Fcb->Identifier.Type == RFSDVCB) {
DbgBreak();
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
ASSERT((Fcb->Identifier.Type == RFSDFCB) &&
(Fcb->Identifier.Size == sizeof(RFSD_FCB)));
if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) {
Status = STATUS_FILE_DELETED;
_SEH2_LEAVE;
}
Ccb = (PRFSD_CCB) FileObject->FsContext2;
ASSERT(Ccb != NULL);
ASSERT((Ccb->Identifier.Type == RFSDCCB) &&
(Ccb->Identifier.Size == sizeof(RFSD_CCB)));
Irp = IrpContext->Irp;
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
FileInformationClass =
IoStackLocation->Parameters.SetFile.FileInformationClass;
Length = IoStackLocation->Parameters.SetFile.Length;
Buffer = Irp->AssociatedIrp.SystemBuffer;
if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY)) {
if (FileInformationClass == FileDispositionInformation ||
FileInformationClass == FileRenameInformation ||
FileInformationClass == FileLinkInformation) {
#ifdef _MSC_VER
#pragma prefast( suppress: 28137, "by design" )
#endif
if (!ExAcquireResourceExclusiveLite(
&Vcb->MainResource,
IrpContext->IsSynchronous )) {
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
VcbResourceAcquired = TRUE;
}
} else if (!FlagOn(Fcb->Flags, FCB_PAGE_FILE)) {
#ifdef _MSC_VER
#pragma prefast( suppress: 28137, "by design" )
#endif
if (!ExAcquireResourceExclusiveLite(
&Fcb->MainResource,
IrpContext->IsSynchronous )) {
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
FcbMainResourceAcquired = TRUE;
}
if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY)) {
if (FileInformationClass != FilePositionInformation) {
Status = STATUS_MEDIA_WRITE_PROTECTED;
_SEH2_LEAVE;
}
}
if (FileInformationClass == FileDispositionInformation ||
FileInformationClass == FileRenameInformation ||
FileInformationClass == FileLinkInformation ||
FileInformationClass == FileAllocationInformation ||
FileInformationClass == FileEndOfFileInformation) {
#ifdef _MSC_VER
#pragma prefast( suppress: 28137, "by design" )
#endif
if (!ExAcquireResourceExclusiveLite(
&Fcb->PagingIoResource,
IrpContext->IsSynchronous )) {
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
FcbPagingIoResourceAcquired = TRUE;
}
/*
if (FileInformationClass != FileDispositionInformation
&& FlagOn(Fcb->Flags, FCB_DELETE_PENDING))
{
Status = STATUS_DELETE_PENDING;
_SEH2_LEAVE;
}
*/
switch (FileInformationClass) {
#if !RFSD_READ_ONLY
#if 0
case FileBasicInformation:
{
PFILE_BASIC_INFORMATION FBI = (PFILE_BASIC_INFORMATION) Buffer;
PRFSD_INODE RfsdInode = Fcb->Inode;
if (FBI->CreationTime.QuadPart) {
RfsdInode->i_ctime = (ULONG)(RfsdInodeTime(FBI->CreationTime));
}
if (FBI->LastAccessTime.QuadPart) {
RfsdInode->i_atime = (ULONG)(RfsdInodeTime(FBI->LastAccessTime));
}
if (FBI->LastWriteTime.QuadPart) {
RfsdInode->i_mtime = (ULONG)(RfsdInodeTime(FBI->LastWriteTime));
}
if (IsFlagOn(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY)) {
RfsdSetReadOnly(Fcb->Inode->i_mode);
SetFlag(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_READONLY);
} else {
RfsdSetWritable(Fcb->Inode->i_mode);
ClearFlag(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_READONLY);
}
if(RfsdSaveInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, RfsdInode)) {
Status = STATUS_SUCCESS;
}
if (FBI->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
} else {
ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE);
}
NotifyFilter = FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_LAST_WRITE ;
Status = STATUS_SUCCESS;
}
break;
case FileAllocationInformation:
{
PFILE_ALLOCATION_INFORMATION FAI = (PFILE_ALLOCATION_INFORMATION)Buffer;
if (FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) {
Status = STATUS_INVALID_DEVICE_REQUEST;
_SEH2_LEAVE;
}
if ( FAI->AllocationSize.QuadPart ==
Fcb->Header.AllocationSize.QuadPart) {
Status = STATUS_SUCCESS;
} else if ( FAI->AllocationSize.QuadPart >
Fcb->Header.AllocationSize.QuadPart ) {
Status = RfsdExpandFile(
IrpContext,
Vcb, Fcb,
&(FAI->AllocationSize));
if (NT_SUCCESS(Status)) {
RfsdSaveInode( IrpContext,
Vcb,
Fcb->RfsdMcb->Inode,
Fcb->Inode );
}
} else {
if (MmCanFileBeTruncated(&(Fcb->SectionObject), &(FAI->AllocationSize))) {
LARGE_INTEGER EndOfFile;
EndOfFile.QuadPart = FAI->AllocationSize.QuadPart +
(LONGLONG)(Vcb->BlockSize - 1);
Status = RfsdTruncateFile(IrpContext, Vcb, Fcb, &(EndOfFile));
if (NT_SUCCESS(Status)) {
if ( FAI->AllocationSize.QuadPart <
Fcb->Header.FileSize.QuadPart) {
Fcb->Header.FileSize.QuadPart =
FAI->AllocationSize.QuadPart;
}
RfsdSaveInode( IrpContext,
Vcb,
Fcb->RfsdMcb->Inode,
Fcb->Inode);
}
} else {
Status = STATUS_USER_MAPPED_FILE;
_SEH2_LEAVE;
}
}
if (NT_SUCCESS(Status)) {
CcSetFileSizes(FileObject,
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
NotifyFilter = FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE ;
}
}
break;
case FileEndOfFileInformation:
{
PFILE_END_OF_FILE_INFORMATION FEOFI = (PFILE_END_OF_FILE_INFORMATION) Buffer;
BOOLEAN CacheInitialized = FALSE;
if (IsDirectory(Fcb)) {
Status = STATUS_INVALID_DEVICE_REQUEST;
_SEH2_LEAVE;
}
if (FEOFI->EndOfFile.HighPart != 0) {
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
if (IoStackLocation->Parameters.SetFile.AdvanceOnly) {
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
(FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
!FlagOn(Irp->Flags, IRP_PAGING_IO)) {
ASSERT( !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) );
CcInitializeCacheMap(
FileObject,
(PCC_FILE_SIZES)&(Fcb->Header.AllocationSize),
FALSE,
&(RfsdGlobal->CacheManagerNoOpCallbacks),
Fcb );
CacheInitialized = TRUE;
}
if ( FEOFI->EndOfFile.QuadPart ==
Fcb->Header.AllocationSize.QuadPart) {
Status = STATUS_SUCCESS;
} else if ( FEOFI->EndOfFile.QuadPart >
Fcb->Header.AllocationSize.QuadPart) {
LARGE_INTEGER FileSize = Fcb->Header.FileSize;
Status = RfsdExpandFile(IrpContext, Vcb, Fcb, &(FEOFI->EndOfFile));
if (NT_SUCCESS(Status)) {
Fcb->Header.FileSize.QuadPart = FEOFI->EndOfFile.QuadPart;
Fcb->Inode->i_size = FEOFI->EndOfFile.QuadPart;
Fcb->Header.ValidDataLength.QuadPart =
(LONGLONG)(0x7fffffffffffffff);
RfsdSaveInode( IrpContext,
Vcb,
Fcb->RfsdMcb->Inode,
Fcb->Inode);
CcSetFileSizes(FileObject,
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
RfsdZeroHoles( IrpContext,
Vcb, FileObject,
FileSize.QuadPart,
Fcb->Header.AllocationSize.QuadPart -
FileSize.QuadPart );
NotifyFilter = FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE ;
}
} else {
if (MmCanFileBeTruncated(&(Fcb->SectionObject), &(FEOFI->EndOfFile))) {
LARGE_INTEGER EndOfFile = FEOFI->EndOfFile;
EndOfFile.QuadPart = EndOfFile.QuadPart +
(LONGLONG)(Vcb->BlockSize - 1);
Status = RfsdTruncateFile(IrpContext, Vcb, Fcb, &(EndOfFile));
if (NT_SUCCESS(Status)) {
Fcb->Header.FileSize.QuadPart = FEOFI->EndOfFile.QuadPart;
Fcb->Inode->i_size = FEOFI->EndOfFile.QuadPart;
RfsdSaveInode( IrpContext,
Vcb,
Fcb->RfsdMcb->Inode,
Fcb->Inode);
CcSetFileSizes(FileObject,
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
NotifyFilter = FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE ;
}
} else {
Status = STATUS_USER_MAPPED_FILE;
_SEH2_LEAVE;
}
}
}
break;
case FileDispositionInformation:
{
PFILE_DISPOSITION_INFORMATION FDI = (PFILE_DISPOSITION_INFORMATION)Buffer;
Status = RfsdSetDispositionInfo(IrpContext, Vcb, Fcb, FDI->DeleteFile);
}
break;
case FileRenameInformation:
{
Status = RfsdSetRenameInfo(IrpContext, Vcb, Fcb);
}
break;
#endif // 0
#endif // !RFSD_READ_ONLY
//
// This is the only set file information request supported on read
// only file systems
//
case FilePositionInformation:
{
PFILE_POSITION_INFORMATION FilePositionInformation;
if (Length < sizeof(FILE_POSITION_INFORMATION)) {
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer;
if ((FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) &&
(FilePositionInformation->CurrentByteOffset.LowPart &
DeviceObject->AlignmentRequirement) ) {
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
FileObject->CurrentByteOffset =
FilePositionInformation->CurrentByteOffset;
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
break;
default:
Status = STATUS_INVALID_INFO_CLASS;
}
} _SEH2_FINALLY {
if (FcbPagingIoResourceAcquired) {
ExReleaseResourceForThreadLite(
&Fcb->PagingIoResource,
ExGetCurrentResourceThread() );
}
if (NT_SUCCESS(Status) && (NotifyFilter != 0)) {
RfsdNotifyReportChange(
IrpContext,
Vcb,
Fcb,
NotifyFilter,
FILE_ACTION_MODIFIED );
}
if (FcbMainResourceAcquired) {
ExReleaseResourceForThreadLite(
&Fcb->MainResource,
ExGetCurrentResourceThread() );
}
if (VcbResourceAcquired) {
ExReleaseResourceForThreadLite(
&Vcb->MainResource,
ExGetCurrentResourceThread() );
}
if (!IrpContext->ExceptionInProgress) {
if (Status == STATUS_PENDING) {
RfsdQueueRequest(IrpContext);
} else {
RfsdCompleteIrpContext(IrpContext, Status);
}
}
} _SEH2_END;
return Status;
}
#if !RFSD_READ_ONLY
NTSTATUS
RfsdExpandFile( PRFSD_IRP_CONTEXT IrpContext,
PRFSD_VCB Vcb, PRFSD_FCB Fcb,
PLARGE_INTEGER AllocationSize)
{
ULONG dwRet = 0;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
if (AllocationSize->QuadPart <= Fcb->Header.AllocationSize.QuadPart) {
return Status;
}
if (((LONGLONG)SUPER_BLOCK->s_free_blocks_count) * Vcb->BlockSize <=
(AllocationSize->QuadPart - Fcb->Header.AllocationSize.QuadPart) ) {
RfsdPrint((DBG_ERROR, "RfsdExpandFile: There is no enough disk space available.\n"));
return STATUS_DISK_FULL;
}
while (NT_SUCCESS(Status) && (AllocationSize->QuadPart > Fcb->Header.AllocationSize.QuadPart)) {
Status = RfsdExpandInode(IrpContext, Vcb, Fcb, &dwRet);
}
return Status;
}
NTSTATUS
RfsdTruncateFile( PRFSD_IRP_CONTEXT IrpContext,
PRFSD_VCB Vcb, PRFSD_FCB Fcb,
PLARGE_INTEGER AllocationSize)
{
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
while (NT_SUCCESS(Status) && (AllocationSize->QuadPart <
Fcb->Header.AllocationSize.QuadPart)) {
Status= RfsdTruncateInode(IrpContext, Vcb, Fcb);
}
return Status;
}
NTSTATUS
RfsdSetDispositionInfo(
PRFSD_IRP_CONTEXT IrpContext,
PRFSD_VCB Vcb,
PRFSD_FCB Fcb,
BOOLEAN bDelete)
{
PIRP Irp = IrpContext->Irp;
PIO_STACK_LOCATION IrpSp;
PAGED_CODE();
IrpSp = IoGetCurrentIrpStackLocation(Irp);
RfsdPrint((DBG_INFO, "RfsdSetDispositionInfo: bDelete=%x\n", bDelete));
if (bDelete) {
RfsdPrint((DBG_INFO, "RfsdSetDispositionInformation: MmFlushImageSection on %s.\n",
Fcb->AnsiFileName.Buffer));
if (!MmFlushImageSection( &Fcb->SectionObject,
MmFlushForDelete )) {
return STATUS_CANNOT_DELETE;
}
if (RFSD_IS_ROOT_KEY(Fcb->RfsdMcb->Key)) {
return STATUS_CANNOT_DELETE;
}
if (IsDirectory(Fcb)) {
if (!RfsdIsDirectoryEmpty(Vcb, Fcb)) {
return STATUS_DIRECTORY_NOT_EMPTY;
}
}
SetFlag(Fcb->Flags, FCB_DELETE_PENDING);
IrpSp->FileObject->DeletePending = TRUE;
if (IsDirectory(Fcb)) {
FsRtlNotifyFullChangeDirectory( Vcb->NotifySync,
&Vcb->NotifyList,
Fcb,
NULL,
FALSE,
FALSE,
0,
NULL,
NULL,
NULL );
}
} else {
ClearFlag(Fcb->Flags, FCB_DELETE_PENDING);
IrpSp->FileObject->DeletePending = FALSE;
}
return STATUS_SUCCESS;
}
NTSTATUS
RfsdSetRenameInfo(
PRFSD_IRP_CONTEXT IrpContext,
PRFSD_VCB Vcb,
PRFSD_FCB Fcb )
{
PRFSD_FCB TargetDcb;
PRFSD_MCB TargetMcb;
PRFSD_MCB Mcb;
RFSD_INODE Inode;
UNICODE_STRING FileName;
NTSTATUS Status;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
PFILE_OBJECT FileObject;
PFILE_OBJECT TargetObject;
BOOLEAN ReplaceIfExists;
BOOLEAN bMove = FALSE;
PFILE_RENAME_INFORMATION FRI;
PAGED_CODE();
#if 0
if (Fcb->RfsdMcb->Inode == RFSD_ROOT_INO) {
Status = STATUS_INVALID_PARAMETER;
goto errorout;
}
Irp = IrpContext->Irp;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
FileObject = IrpSp->FileObject;
TargetObject = IrpSp->Parameters.SetFile.FileObject;
ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
FRI = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
if (TargetObject == NULL) {
UNICODE_STRING NewName;
NewName.Buffer = FRI->FileName;
NewName.MaximumLength = NewName.Length = (USHORT)FRI->FileNameLength;
while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] == L'\\') {
NewName.Buffer[NewName.Length/2 - 1] = 0;
NewName.Length -= 2;
}
while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] != L'\\') {
NewName.Length -= 2;
}
NewName.Buffer = (USHORT *)((UCHAR *)NewName.Buffer + NewName.Length);
NewName.Length = (USHORT)(FRI->FileNameLength - NewName.Length);
FileName = NewName;
TargetDcb = NULL;
TargetMcb = Fcb->RfsdMcb->Parent;
if (FileName.Length >= RFSD_NAME_LEN*sizeof(USHORT)) {
Status = STATUS_OBJECT_NAME_INVALID;
goto errorout;
}
} else {
TargetDcb = (PRFSD_FCB)(TargetObject->FsContext);
if (!TargetDcb || TargetDcb->Vcb != Vcb) {
DbgBreak();
Status = STATUS_INVALID_PARAMETER;
goto errorout;
}
TargetMcb = TargetDcb->RfsdMcb;
FileName = TargetObject->FileName;
}
if (FsRtlDoesNameContainWildCards(&FileName)) {
Status = STATUS_OBJECT_NAME_INVALID;
goto errorout;
}
if (TargetMcb->Inode == Fcb->RfsdMcb->Parent->Inode) {
if (FsRtlAreNamesEqual( &FileName,
&(Fcb->RfsdMcb->ShortName),
FALSE,
NULL )) {
Status = STATUS_SUCCESS;
goto errorout;
}
} else {
bMove = TRUE;
}
TargetDcb = TargetMcb->RfsdFcb;
if (!TargetDcb)
TargetDcb = RfsdCreateFcbFromMcb(Vcb, TargetMcb);
if ((TargetMcb->Inode != Fcb->RfsdMcb->Parent->Inode) &&
(Fcb->RfsdMcb->Parent->RfsdFcb == NULL) ) {
RfsdCreateFcbFromMcb(Vcb, Fcb->RfsdMcb->Parent);
}
if (!TargetDcb || !(Fcb->RfsdMcb->Parent->RfsdFcb)) {
Status = STATUS_UNSUCCESSFUL;
goto errorout;
}
Mcb = NULL;
Status = RfsdLookupFileName(
Vcb,
&FileName,
TargetMcb,
&Mcb,
&Inode );
if (NT_SUCCESS(Status)) {
if ( (!ReplaceIfExists) ||
(IsFlagOn(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) ||
(IsFlagOn(Mcb->FileAttr, FILE_ATTRIBUTE_READONLY))) {
Status = STATUS_OBJECT_NAME_COLLISION;
goto errorout;
}
if (ReplaceIfExists) {
Status = STATUS_NOT_IMPLEMENTED;
goto errorout;
}
}
if (IsDirectory(Fcb)) {
Status = RfsdRemoveEntry( IrpContext, Vcb,
Fcb->RfsdMcb->Parent->RfsdFcb,
RFSD_FT_DIR,
Fcb->RfsdMcb->Inode );
if (!NT_SUCCESS(Status)) {
DbgBreak();
goto errorout;
}
Status = RfsdAddEntry( IrpContext, Vcb,
TargetDcb,
RFSD_FT_DIR,
Fcb->RfsdMcb->Inode,
&FileName );
if (!NT_SUCCESS(Status)) {
DbgBreak();
RfsdAddEntry( IrpContext, Vcb,
Fcb->RfsdMcb->Parent->RfsdFcb,
RFSD_FT_DIR,
Fcb->RfsdMcb->Inode,
&Fcb->RfsdMcb->ShortName );
goto errorout;
}
if( !RfsdSaveInode( IrpContext,
Vcb,
TargetMcb->Inode,
TargetDcb->Inode)) {
Status = STATUS_UNSUCCESSFUL;
DbgBreak();
goto errorout;
}
if( !RfsdSaveInode( IrpContext,
Vcb,
Fcb->RfsdMcb->Parent->Inode,
Fcb->RfsdMcb->Parent->RfsdFcb->Inode)) {
Status = STATUS_UNSUCCESSFUL;
DbgBreak();
goto errorout;
}
Status = RfsdSetParentEntry( IrpContext, Vcb, Fcb,
Fcb->RfsdMcb->Parent->Inode,
TargetDcb->RfsdMcb->Inode );
if (!NT_SUCCESS(Status)) {
DbgBreak();
goto errorout;
}
} else {
Status = RfsdRemoveEntry( IrpContext, Vcb,
Fcb->RfsdMcb->Parent->RfsdFcb,
RFSD_FT_REG_FILE,
Fcb->RfsdMcb->Inode );
if (!NT_SUCCESS(Status)) {
DbgBreak();
goto errorout;
}
Status = RfsdAddEntry( IrpContext,
Vcb, TargetDcb,
RFSD_FT_REG_FILE,
Fcb->RfsdMcb->Inode,
&FileName );
if (!NT_SUCCESS(Status)) {
DbgBreak();
RfsdAddEntry( IrpContext, Vcb,
Fcb->RfsdMcb->Parent->RfsdFcb,
RFSD_FT_REG_FILE,
Fcb->RfsdMcb->Inode,
&Fcb->RfsdMcb->ShortName );
goto errorout;
}
}
if (NT_SUCCESS(Status)) {
if (Fcb->RfsdMcb->ShortName.MaximumLength < (FileName.Length + 2)) {
ExFreePool(Fcb->RfsdMcb->ShortName.Buffer);
Fcb->RfsdMcb->ShortName.Buffer =
ExAllocatePoolWithTag(PagedPool, FileName.Length + 2, RFSD_POOL_TAG);
if (!Fcb->RfsdMcb->ShortName.Buffer) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
Fcb->RfsdMcb->ShortName.MaximumLength = FileName.Length + 2;
}
{
RtlZeroMemory( Fcb->RfsdMcb->ShortName.Buffer,
Fcb->RfsdMcb->ShortName.MaximumLength);
RtlCopyMemory( Fcb->RfsdMcb->ShortName.Buffer,
FileName.Buffer, FileName.Length);
Fcb->RfsdMcb->ShortName.Length = FileName.Length;
}
#if DBG
Fcb->AnsiFileName.Length = (USHORT)
RfsdUnicodeToOEMSize(&FileName) + 1;
if (Fcb->AnsiFileName.MaximumLength < FileName.Length) {
ExFreePool(Fcb->AnsiFileName.Buffer);
Fcb->AnsiFileName.Buffer =
ExAllocatePoolWithTag(PagedPool, Fcb->AnsiFileName.Length + 1, RFSD_POOL_TAG);
if (!Fcb->AnsiFileName.Buffer) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
RtlZeroMemory( Fcb->AnsiFileName.Buffer,
Fcb->AnsiFileName.Length + 1);
Fcb->AnsiFileName.MaximumLength =
Fcb->AnsiFileName.Length + 1;
}
RfsdUnicodeToOEM( &(Fcb->AnsiFileName),
&FileName );
#endif
if (bMove) {
RfsdNotifyReportChange(
IrpContext,
Vcb,
Fcb,
(IsDirectory(Fcb) ?
FILE_NOTIFY_CHANGE_DIR_NAME :
FILE_NOTIFY_CHANGE_FILE_NAME ),
FILE_ACTION_REMOVED);
} else {
RfsdNotifyReportChange(
IrpContext,
Vcb,
Fcb,
(IsDirectory(Fcb) ?
FILE_NOTIFY_CHANGE_DIR_NAME :
FILE_NOTIFY_CHANGE_FILE_NAME ),
FILE_ACTION_RENAMED_OLD_NAME);
}
RfsdDeleteMcbNode(Vcb, Fcb->RfsdMcb->Parent, Fcb->RfsdMcb);
RfsdAddMcbNode(Vcb, TargetMcb, Fcb->RfsdMcb);
if (bMove) {
RfsdNotifyReportChange(
IrpContext,
Vcb,
Fcb,
(IsDirectory(Fcb) ?
FILE_NOTIFY_CHANGE_DIR_NAME :
FILE_NOTIFY_CHANGE_FILE_NAME ),
FILE_ACTION_ADDED);
} else {
RfsdNotifyReportChange(
IrpContext,
Vcb,
Fcb,
(IsDirectory(Fcb) ?
FILE_NOTIFY_CHANGE_DIR_NAME :
FILE_NOTIFY_CHANGE_FILE_NAME ),
FILE_ACTION_RENAMED_NEW_NAME );
}
}
errorout:
#endif // 0
return 0;//Status;
}
NTSTATUS
RfsdDeleteFile(
PRFSD_IRP_CONTEXT IrpContext,
PRFSD_VCB Vcb,
PRFSD_FCB Fcb )
{
BOOLEAN bRet = FALSE;
LARGE_INTEGER AllocationSize;
PRFSD_FCB Dcb = NULL;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
#if 0
RfsdPrint((DBG_INFO, "RfsdDeleteFile: File %S (%xh) will be deleted!\n",
Fcb->RfsdMcb->ShortName.Buffer, Fcb->RfsdMcb->Inode));
if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) {
return Status;
}
if (FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) {
if (!RfsdIsDirectoryEmpty(Vcb, Fcb)) {
ClearFlag(Fcb->Flags, FCB_DELETE_PENDING);
return STATUS_DIRECTORY_NOT_EMPTY;
}
}
RfsdPrint((DBG_INFO, "RfsdDeleteFile: RFSDSB->S_FREE_BLOCKS = %xh .\n",
Vcb->SuperBlock->s_free_blocks_count));
if (IsDirectory(Fcb)) {
if (Fcb->Inode->i_links_count <= 2) {
} else {
Status = STATUS_CANNOT_DELETE;
}
} else {
if (Fcb->Inode->i_links_count <= 1) {
} else {
Status = STATUS_CANNOT_DELETE;
}
}
if (!NT_SUCCESS(Status)) {
DbgBreak();
return Status;
}
if (Fcb->RfsdMcb->Parent->RfsdFcb) {
Status = RfsdRemoveEntry(
IrpContext, Vcb,
Fcb->RfsdMcb->Parent->RfsdFcb,
(FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) ?
RFSD_FT_DIR : RFSD_FT_REG_FILE),
Fcb->RfsdMcb->Inode);
} else {
Dcb = RfsdCreateFcbFromMcb(Vcb, Fcb->RfsdMcb->Parent);
if (Dcb) {
Status = RfsdRemoveEntry(
IrpContext, Vcb, Dcb,
(FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) ?
RFSD_FT_DIR : RFSD_FT_REG_FILE),
Fcb->RfsdMcb->Inode);
}
}
if (NT_SUCCESS(Status)) {
LARGE_INTEGER SysTime;
KeQuerySystemTime(&SysTime);
AllocationSize.QuadPart = (LONGLONG)0;
Status = RfsdTruncateFile(IrpContext, Vcb, Fcb, &AllocationSize);
//
// Update the inode's data length . It should be ZERO if succeeds.
//
if (Fcb->Header.FileSize.QuadPart > Fcb->Header.AllocationSize.QuadPart) {
Fcb->Header.FileSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
Fcb->Inode->i_size = Fcb->Header.AllocationSize.QuadPart;
}
Fcb->Inode->i_links_count = 0;
RfsdSaveInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, Fcb->Inode);
if (IsDirectory(Fcb)) {
bRet = RfsdFreeInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, RFSD_FT_DIR);
} else {
bRet = RfsdFreeInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, RFSD_FT_REG_FILE);
}
SetFlag(Fcb->Flags, FCB_FILE_DELETED);
RfsdDeleteMcbNode(Vcb, Fcb->RfsdMcb->Parent, Fcb->RfsdMcb);
} else {
DbgBreak();
RfsdSaveInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, Fcb->Inode);
}
RfsdPrint((DBG_INFO, "RfsdDeleteFile: Succeed... RFSDSB->S_FREE_BLOCKS = %xh .\n",
Vcb->SuperBlock->s_free_blocks_count));
#endif // 0
return Status;
}
#endif // !RFSD_READ_ONLY