347 lines
8.6 KiB
C
347 lines
8.6 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
FilObSup.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the Ntfs File object support routines.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Gary Kimura [GaryKi] 21-May-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "NtfsProc.h"
|
|||
|
|
|||
|
//
|
|||
|
// The debug trace level
|
|||
|
//
|
|||
|
|
|||
|
#define Dbg (DEBUG_TRACE_FILOBSUP)
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, NtfsSetFileObject)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NtfsSetFileObject (
|
|||
|
IN PFILE_OBJECT FileObject,
|
|||
|
IN TYPE_OF_OPEN TypeOfOpen,
|
|||
|
IN PSCB Scb,
|
|||
|
IN PCCB Ccb OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets the file system pointers within the file object
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
FileObject - Supplies a pointer to the file object being modified.
|
|||
|
|
|||
|
TypeOfOpen - Supplies the type of open denoted by the file object.
|
|||
|
This is only used by this procedure for sanity checking.
|
|||
|
|
|||
|
Scb - Supplies a pointer to Scb for the file object.
|
|||
|
|
|||
|
Ccb - Optionally supplies a pointer to a ccb
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ASSERT_FILE_OBJECT( FileObject );
|
|||
|
ASSERT_SCB( Scb );
|
|||
|
ASSERT_OPTIONAL_CCB( Ccb );
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DebugTrace( +1, Dbg, ("NtfsSetFileObject, FileObject = %08lx\n", FileObject) );
|
|||
|
|
|||
|
//
|
|||
|
// Load up the FileObject fields.
|
|||
|
//
|
|||
|
|
|||
|
FileObject->FsContext = Scb;
|
|||
|
FileObject->FsContext2 = Ccb;
|
|||
|
FileObject->Vpb = Scb->Vcb->Vpb;
|
|||
|
|
|||
|
//
|
|||
|
// Typically the I/O manager has already set this flag correctly. The notable
|
|||
|
// exception is when the user did an open by file ID of file record 3, so
|
|||
|
// we're doing a DASD open, but the I/O manager didn't notice, since it only
|
|||
|
// checks for a zero length filename.
|
|||
|
//
|
|||
|
|
|||
|
if (TypeOfOpen == UserVolumeOpen) {
|
|||
|
SetFlag( FileObject->Flags, FO_VOLUME_OPEN );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now store TypeOfOpen if there is a Ccb
|
|||
|
//
|
|||
|
|
|||
|
ASSERT((Ccb != NULL) || (TypeOfOpen == StreamFileOpen) || (TypeOfOpen == UnopenedFileObject));
|
|||
|
if (Ccb != NULL) {
|
|||
|
Ccb->TypeOfOpen = (UCHAR)TypeOfOpen;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this file has the temporary attribute bit set, don't lazy
|
|||
|
// write it unless absolutely necessary.
|
|||
|
//
|
|||
|
|
|||
|
if (FlagOn( Scb->ScbState, SCB_STATE_TEMPORARY )) {
|
|||
|
SetFlag( FileObject->Flags, FO_TEMPORARY_FILE );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// And return to our caller
|
|||
|
//
|
|||
|
|
|||
|
DebugTrace( -1, Dbg, ("NtfsSetFileObject -> VOID\n") );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Local support routine
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
NtfsUpdateScbFromFileObject (
|
|||
|
IN PIRP_CONTEXT IrpContext,
|
|||
|
IN PFILE_OBJECT FileObject,
|
|||
|
IN PSCB Scb,
|
|||
|
IN BOOLEAN CheckTimeStamps
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called to update the Scb/Fcb to reflect the changes to
|
|||
|
a file through the fast io path. It only called with a file object which
|
|||
|
represents a user's handle.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
FileObject - This is the file object used in the fast io path.
|
|||
|
|
|||
|
Scb - This is the Scb for this stream.
|
|||
|
|
|||
|
CheckTimeStamps - Indicates whether we want to update the time stamps from the
|
|||
|
fast io flags as well. This will be TRUE if our caller will update the standard information,
|
|||
|
attribute header and duplicate info. FALSE if only the attribute header and duplicate info.
|
|||
|
The latter case is the valid data length callback from the cache manager.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PFCB Fcb = Scb->Fcb;
|
|||
|
ULONG CcbFlags;
|
|||
|
ULONG ScbFlags = 0;
|
|||
|
LONGLONG CurrentTime;
|
|||
|
|
|||
|
//
|
|||
|
// If the size of the main data stream is not part of the Fcb then update it
|
|||
|
// now and set the correct Fcb flag.
|
|||
|
//
|
|||
|
|
|||
|
if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) {
|
|||
|
|
|||
|
if (Fcb->Info.FileSize != Scb->Header.FileSize.QuadPart) {
|
|||
|
|
|||
|
Fcb->Info.FileSize = Scb->Header.FileSize.QuadPart;
|
|||
|
SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_SIZE );
|
|||
|
}
|
|||
|
|
|||
|
if (Fcb->Info.AllocatedLength != Scb->TotalAllocated) {
|
|||
|
|
|||
|
Fcb->Info.AllocatedLength = Scb->TotalAllocated;
|
|||
|
SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_ALLOC_SIZE );
|
|||
|
}
|
|||
|
|
|||
|
if (FlagOn( FileObject->Flags, FO_FILE_SIZE_CHANGED )) {
|
|||
|
|
|||
|
SetFlag( ScbFlags, SCB_STATE_CHECK_ATTRIBUTE_SIZE );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remember to update the size in the attribute header for named streams as well.
|
|||
|
//
|
|||
|
|
|||
|
} else if (FlagOn( FileObject->Flags, FO_FILE_SIZE_CHANGED )) {
|
|||
|
|
|||
|
SetFlag( ScbFlags, SCB_STATE_NOTIFY_RESIZE_STREAM | SCB_STATE_CHECK_ATTRIBUTE_SIZE );
|
|||
|
}
|
|||
|
|
|||
|
ClearFlag( FileObject->Flags, FO_FILE_SIZE_CHANGED );
|
|||
|
|
|||
|
//
|
|||
|
// Check whether to update the time stamps if our caller requested it.
|
|||
|
//
|
|||
|
|
|||
|
if (CheckTimeStamps && !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
|
|||
|
|
|||
|
BOOLEAN UpdateLastAccess = FALSE;
|
|||
|
BOOLEAN UpdateLastChange = FALSE;
|
|||
|
BOOLEAN UpdateLastModify = FALSE;
|
|||
|
BOOLEAN SetArchive = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the Ccb flags to a local variable. Then we won't have to test
|
|||
|
// for the existence of the Ccb each time.
|
|||
|
//
|
|||
|
|
|||
|
CcbFlags = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Capture the real flags if present and clear them since we will update the Scb/Fcb.
|
|||
|
//
|
|||
|
|
|||
|
if (FileObject->FsContext2 != NULL) {
|
|||
|
|
|||
|
CcbFlags = ((PCCB) FileObject->FsContext2)->Flags;
|
|||
|
ClearFlag( ((PCCB) FileObject->FsContext2)->Flags,
|
|||
|
(CCB_FLAG_UPDATE_LAST_MODIFY |
|
|||
|
CCB_FLAG_UPDATE_LAST_CHANGE |
|
|||
|
CCB_FLAG_SET_ARCHIVE) );
|
|||
|
}
|
|||
|
|
|||
|
NtfsGetCurrentTime( IrpContext, CurrentTime );
|
|||
|
|
|||
|
//
|
|||
|
// If there was a write to the file then update the last change, last access
|
|||
|
// and last write and the archive bit.
|
|||
|
//
|
|||
|
|
|||
|
if (FlagOn( FileObject->Flags, FO_FILE_MODIFIED )) {
|
|||
|
|
|||
|
UpdateLastModify =
|
|||
|
UpdateLastAccess =
|
|||
|
UpdateLastChange = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Otherwise test each of the individual bits in the file object and
|
|||
|
// Ccb.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (FlagOn( FileObject->Flags, FO_FILE_FAST_IO_READ )) {
|
|||
|
|
|||
|
UpdateLastAccess = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (FlagOn( CcbFlags, CCB_FLAG_UPDATE_LAST_CHANGE )) {
|
|||
|
|
|||
|
UpdateLastChange = TRUE;
|
|||
|
|
|||
|
if (FlagOn( CcbFlags, CCB_FLAG_UPDATE_LAST_MODIFY )) {
|
|||
|
|
|||
|
UpdateLastModify = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (!FlagOn( CcbFlags, CCB_FLAG_SET_ARCHIVE )) {
|
|||
|
|
|||
|
SetArchive = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now set the correct Fcb bits.
|
|||
|
//
|
|||
|
|
|||
|
if (UpdateLastChange) {
|
|||
|
|
|||
|
if (SetArchive) {
|
|||
|
|
|||
|
ASSERTMSG( "conflict with flush",
|
|||
|
ExIsResourceAcquiredSharedLite( Fcb->Resource ) ||
|
|||
|
(Fcb->PagingIoResource != NULL &&
|
|||
|
ExIsResourceAcquiredSharedLite( Fcb->PagingIoResource )));
|
|||
|
|
|||
|
SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ARCHIVE );
|
|||
|
SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
|
|||
|
SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
|
|||
|
}
|
|||
|
|
|||
|
if (!FlagOn( CcbFlags, CCB_FLAG_USER_SET_LAST_CHANGE_TIME )) {
|
|||
|
|
|||
|
Fcb->Info.LastChangeTime = CurrentTime;
|
|||
|
SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_LAST_CHANGE );
|
|||
|
SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
|
|||
|
}
|
|||
|
|
|||
|
if (UpdateLastModify) {
|
|||
|
|
|||
|
//
|
|||
|
// Remember a change to a named data stream.
|
|||
|
//
|
|||
|
|
|||
|
if (!FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA ) &&
|
|||
|
(Scb->AttributeTypeCode == $DATA)) {
|
|||
|
|
|||
|
SetFlag( ScbFlags, SCB_STATE_NOTIFY_MODIFY_STREAM );
|
|||
|
}
|
|||
|
|
|||
|
if (!FlagOn( CcbFlags, CCB_FLAG_USER_SET_LAST_MOD_TIME )) {
|
|||
|
|
|||
|
Fcb->Info.LastModificationTime = CurrentTime;
|
|||
|
SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_LAST_MOD );
|
|||
|
SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (UpdateLastAccess &&
|
|||
|
!FlagOn( CcbFlags, CCB_FLAG_USER_SET_LAST_ACCESS_TIME ) &&
|
|||
|
!FlagOn( NtfsData.Flags, NTFS_FLAGS_DISABLE_LAST_ACCESS )) {
|
|||
|
|
|||
|
Fcb->CurrentLastAccess = CurrentTime;
|
|||
|
SetFlag( Fcb->InfoFlags, FCB_INFO_UPDATE_LAST_ACCESS );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Clear all of the fast io flags in the file object.
|
|||
|
//
|
|||
|
|
|||
|
ClearFlag( FileObject->Flags, FO_FILE_MODIFIED | FO_FILE_FAST_IO_READ );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now store the Scb flags into the Scb.
|
|||
|
//
|
|||
|
|
|||
|
if (ScbFlags) {
|
|||
|
|
|||
|
NtfsAcquireFsrtlHeader( Scb );
|
|||
|
SetFlag( Scb->ScbState, ScbFlags );
|
|||
|
NtfsReleaseFsrtlHeader( Scb );
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|