📄 fileinfo.c
字号:
if (ModifyLastAccess &&
(Buffer->LastWriteTime.QuadPart == Buffer->LastAccessTime.QuadPart)) {
ModifyLastWrite = TRUE;
LastWriteTime = LastAccessTime;
LargeLastWriteTime = LargeLastAccessTime;
} else {
LargeLastWriteTime = Buffer->LastWriteTime;
//
// Convert the Nt time to a Fat time
//
if ( !FatNtTimeToFatTime( IrpContext,
&LargeLastWriteTime,
TRUE,
&LastWriteTime,
NULL )) {
//
// Special case the value 12/31/79 and treat this as 1/1/80.
// This '79 value can happen because of time zone issues.
//
if ((LargeLastWriteTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
(LargeLastWriteTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
LastWriteTime = FatTimeJanOne1980;
LargeLastWriteTime = FatLocalJanOne1980;
} else {
DebugTrace(0, Dbg, "Invalid LastWriteTime\n", 0);
try_return( Status = STATUS_INVALID_PARAMETER );
}
}
ModifyLastWrite = TRUE;
}
}
//
// Check if the user specified a non zero file attributes byte
//
if (Buffer->FileAttributes != 0) {
//
// Only permit the attributes that FAT understands. The rest are silently
// dropped on the floor.
//
Attributes = (UCHAR)(Buffer->FileAttributes & (FILE_ATTRIBUTE_READONLY |
FILE_ATTRIBUTE_HIDDEN |
FILE_ATTRIBUTE_SYSTEM |
FILE_ATTRIBUTE_DIRECTORY |
FILE_ATTRIBUTE_ARCHIVE));
//
// Make sure that for a file the directory bit is not set
// and that for a directory the bit is set.
//
if (NodeType(Fcb) == FAT_NTC_FCB) {
if (FlagOn(Buffer->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
DebugTrace(0, Dbg, "Attempt to set dir attribute on file\n", 0);
try_return( Status = STATUS_INVALID_PARAMETER );
}
} else {
Attributes |= FAT_DIRENT_ATTR_DIRECTORY;
}
//
// Mark the FcbState temporary flag correctly.
//
if (FlagOn(Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY)) {
//
// Don't allow the temporary bit to be set on directories.
//
if (NodeType(Fcb) == FAT_NTC_DCB) {
DebugTrace(0, Dbg, "No temporary directories\n", 0);
try_return( Status = STATUS_INVALID_PARAMETER );
}
SetFlag( Fcb->FcbState, FCB_STATE_TEMPORARY );
SetFlag( IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags,
FO_TEMPORARY_FILE );
} else {
ClearFlag( Fcb->FcbState, FCB_STATE_TEMPORARY );
ClearFlag( IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags,
FO_TEMPORARY_FILE );
}
//
// Set the new attributes byte, and mark the bcb dirty
//
Fcb->DirentFatFlags = Attributes;
Dirent->Attributes = Attributes;
NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
}
if ( ModifyCreation ) {
//
// Set the new last write time in the dirent, and mark
// the bcb dirty
//
Fcb->CreationTime = LargeCreationTime;
Dirent->CreationTime = CreationTime;
Dirent->CreationMSec = CreationMSec;
NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
//
// Now we have to round the time in the Fcb up to the
// nearest tem msec.
//
Fcb->CreationTime.QuadPart =
((Fcb->CreationTime.QuadPart + AlmostTenMSec) /
TenMSec) * TenMSec;
//
// Now because the user just set the creation time we
// better not set the creation time on close
//
SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_CREATION );
}
if ( ModifyLastAccess ) {
//
// Set the new last write time in the dirent, and mark
// the bcb dirty
//
Fcb->LastAccessTime = LargeLastAccessTime;
Dirent->LastAccessDate = LastAccessDate;
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
//
// Now we have to truncate the time in the Fcb down to the
// current day. This has to be in LocalTime though, so first
// convert to local, trunacate, then set back to GMT.
//
ExSystemTimeToLocalTime( &Fcb->LastAccessTime,
&Fcb->LastAccessTime );
Fcb->LastAccessTime.QuadPart =
(Fcb->LastAccessTime.QuadPart /
FatOneDay.QuadPart) * FatOneDay.QuadPart;
ExLocalTimeToSystemTime( &Fcb->LastAccessTime,
&Fcb->LastAccessTime );
//
// Now because the user just set the last access time we
// better not set the last access time on close
//
SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_LAST_ACCESS );
}
if ( ModifyLastWrite ) {
//
// Set the new last write time in the dirent, and mark
// the bcb dirty
//
Fcb->LastWriteTime = LargeLastWriteTime;
Dirent->LastWriteTime = LastWriteTime;
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
//
// Now we have to round the time in the Fcb up to the
// nearest two seconds.
//
Fcb->LastWriteTime.QuadPart =
((Fcb->LastWriteTime.QuadPart + AlmostTwoSeconds) /
TwoSeconds) * TwoSeconds;
//
// Now because the user just set the last write time we
// better not set the last write time on close
//
SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_LAST_WRITE );
}
//
// If we modified any of the values, we report this to the notify
// package.
//
// We also take this opportunity to set the current file size and
// first cluster in the Dirent in order to support a server hack.
//
if (NotifyFilter != 0) {
if (NodeType(Fcb) == FAT_NTC_FCB) {
Dirent->FileSize = Fcb->Header.FileSize.LowPart;
Dirent->FirstClusterOfFile = (USHORT)Fcb->FirstClusterOfFile;
if (FatIsFat32(Fcb->Vcb)) {
Dirent->FirstClusterOfFileHi =
(USHORT)(Fcb->FirstClusterOfFile >> 16);
}
}
FatNotifyReportChange( IrpContext,
Fcb->Vcb,
Fcb,
NotifyFilter,
FILE_ACTION_MODIFIED );
FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE );
}
try_exit: NOTHING;
} finally {
DebugUnwind( FatSetBasicInfo );
FatUnpinBcb( IrpContext, DirentBcb );
DebugTrace(-1, Dbg, "FatSetBasicInfo -> %08lx\n", Status);
}
return Status;
}
//
// Internal Support Routine
//
NTSTATUS
FatSetDispositionInfo (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp,
IN PFILE_OBJECT FileObject,
IN PFCB Fcb
)
/*++
Routine Description:
This routine performs the set disposition information for fat. It either
completes the request or enqueues it off to the fsp.
Arguments:
Irp - Supplies the irp being processed
FileObject - Supplies the file object being processed
Fcb - Supplies the Fcb or Dcb being processed, already known not to
be the root dcb
Return Value:
NTSTATUS - The result of this operation if it completes without
an exception.
--*/
{
PFILE_DISPOSITION_INFORMATION Buffer;
PBCB Bcb;
PDIRENT Dirent;
DebugTrace(+1, Dbg, "FatSetDispositionInfo...\n", 0);
Buffer = Irp->AssociatedIrp.SystemBuffer;
//
// Check if the user wants to delete the file or not delete
// the file
//
if (Buffer->DeleteFile) {
//
// Check if the file is marked read only
//
if (FlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_READ_ONLY)) {
DebugTrace(-1, Dbg, "Cannot delete readonly file\n", 0);
return STATUS_CANNOT_DELETE;
}
//
// Make sure there is no process mapping this file as an image.
//
if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers,
MmFlushForDelete )) {
DebugTrace(-1, Dbg, "Cannot delete user mapped image\n", 0);
return STATUS_CANNOT_DELETE;
}
//
// Check if this is a dcb and if so then only allow
// the request if the directory is empty.
//
if (NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
DebugTrace(-1, Dbg, "Cannot delete root Directory\n", 0);
return STATUS_CANNOT_DELETE;
}
if (NodeType(Fcb) == FAT_NTC_DCB) {
DebugTrace(-1, Dbg, "User wants to delete a directory\n", 0);
//
// Check if the directory is empty
//
if ( !FatIsDirectoryEmpty(IrpContext, Fcb) ) {
DebugTrace(-1, Dbg, "Directory is not empty\n", 0);
return STATUS_DIRECTORY_NOT_EMPTY;
}
}
//
// If this is a floppy, touch the volume so to verify that it
// is not write protected.
//
if ( FlagOn(Fcb->Vcb->Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
PVCB Vcb;
PBCB LocalBcb = NULL;
UCHAR *LocalBuffer;
UCHAR TmpChar;
ULONG BytesToMap;
IO_STATUS_BLOCK Iosb;
Vcb = Fcb->Vcb;
BytesToMap = Vcb->AllocationSupport.FatIndexBitSize == 12 ?
FatReservedBytes(&Vcb->Bpb) +
FatBytesPerFat(&Vcb->Bpb):PAGE_SIZE;
FatReadVolumeFile( IrpContext,
Vcb,
0,
BytesToMap,
&LocalBcb,
(PVOID *)&LocalBuffer );
try {
if (!CcPinMappedData( Vcb->VirtualVolumeFile,
&FatLargeZero,
BytesToMap,
BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
&LocalBcb )) {
//
// Could not pin the data without waiting (cache miss).
//
FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
}
//
// Make Mm, myself, and Cc think the byte is dirty, and then
// force a writethrough.
//
LocalBuffer += FatReservedBytes(&Vcb->Bpb);
TmpChar = LocalBuffer[0];
LocalBuffer[0] = TmpChar;
FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb,
FatReservedBytes( &Vcb->Bpb ),
FatReservedBytes( &Vcb->Bpb ),
Vcb->Bpb.BytesPerSector );
} finally {
if (AbnormalTermination() && (LocalBcb != NULL)) {
FatUnpinBcb( IrpContext, LocalBcb );
}
}
CcRepinBcb( LocalBcb );
CcSetDirtyPinnedData( LocalBcb, NULL );
CcUnpinData( LocalBcb );
DbgDoit( ASSERT( IrpContext->PinCount ));
DbgDoit( IrpContext->PinCount -= 1 );
CcUnpinRepinnedBcb( LocalBcb, TRUE, &Iosb );
//
// If this was not successful, raise the status.
//
if ( !NT_SUCCESS(Iosb.Status) ) {
FatNormalizeAndRaiseStatus( IrpContext, Iosb.Status );
}
} else {
//
// Just set a Bcb dirty here. The above code was only there to
// detect a write protected floppy, while the below code works
// for any write protected media and only takes a hit when the
// volume in clean.
//
FatGetDirentFromFcbOrDcb( IrpContext,
Fcb,
FALSE,
&Dirent,
&Bcb );
//
// This has to work for the usual reasons (we verified the Fcb within
// volume synch).
//
try {
FatSetDirtyBcb( IrpContext, Bcb, Fcb->Vcb, TRUE );
} finally {
FatUnpinBcb( IrpContext, Bcb );
}
}
//
// At this point either we have a file or an empty directory
// so we know the delete can proceed.
//
SetFlag( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
FileObject->DeletePending = TRUE;
//
// If this is a directory then report this delete pending to
// the dir notify package.
//
if (NodeType(Fcb) == FAT_NTC_DCB) {
FsRtlNotifyFullChangeDirectory( Fcb->Vcb->NotifySync,
&Fcb->Vcb->DirNotifyList,
FileObject->FsContext,
NU
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -