You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7514 lines
193 KiB
7514 lines
193 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
NtfsProc.h
|
|
|
|
Abstract:
|
|
|
|
This module defines all of the globally used procedures in the Ntfs
|
|
file system.
|
|
|
|
Author:
|
|
|
|
Brian Andrew [BrianAn] 21-May-1991
|
|
David Goebel [DavidGoe]
|
|
Gary Kimura [GaryKi]
|
|
Tom Miller [TomM]
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#ifndef _NTFSPROC_
|
|
#define _NTFSPROC_
|
|
|
|
#pragma warning(error:4100) // Unreferenced formal parameter
|
|
#pragma warning(error:4101) // Unreferenced local variable
|
|
#pragma warning(error:4705) // Statement has no effect
|
|
#pragma warning(disable:4116) // unnamed type definition in parentheses
|
|
|
|
#define RTL_USE_AVL_TABLES 0
|
|
|
|
#ifndef KDEXTMODE
|
|
|
|
#include <ntifs.h>
|
|
|
|
#else
|
|
|
|
#include <ntos.h>
|
|
#include <zwapi.h>
|
|
#include <FsRtl.h>
|
|
#include <ntrtl.h>
|
|
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <lfs.h>
|
|
#include <ntdddisk.h>
|
|
#include <NtIoLogc.h>
|
|
#include <elfmsg.h>
|
|
|
|
#include "nodetype.h"
|
|
#include "Ntfs.h"
|
|
|
|
#ifndef INLINE
|
|
// definition of inline
|
|
#define INLINE __inline
|
|
#endif
|
|
|
|
#include <ntfsexp.h>
|
|
|
|
#include "NtfsStru.h"
|
|
#include "NtfsData.h"
|
|
#include "NtfsLog.h"
|
|
|
|
//
|
|
// Tag all of our allocations if tagging is turned on
|
|
//
|
|
|
|
//
|
|
// Default module pool tag
|
|
//
|
|
|
|
#define MODULE_POOL_TAG ('0ftN')
|
|
|
|
#if 0
|
|
#define NtfsVerifySizes(s) (ASSERT( (s)->ValidDataLength.QuadPart <= (s)->FileSize.QuadPart && (s)->FileSize.QuadPart <= (s)->AllocationSize.QuadPart ))
|
|
#define NtfsVerifySizesLongLong(s) (ASSERT( (s)->ValidDataLength <= (s)->FileSize && (s)->FileSize <= (s)->AllocationSize ))
|
|
#else // !DBG
|
|
#define NtfsVerifySizes(s)
|
|
#define NtfsVerifySizesLongLong(s)
|
|
#endif // !DBG
|
|
|
|
#if !(DBG && i386 && defined (NTFSPOOLCHECK))
|
|
|
|
//
|
|
// Non-debug allocate and free goes directly to the FsRtl routines
|
|
//
|
|
|
|
#define NtfsAllocatePoolWithTagNoRaise(a,b,c) ExAllocatePoolWithTag((a),(b),(c))
|
|
#define NtfsAllocatePoolWithTag(a,b,c) FsRtlAllocatePoolWithTag((a),(b),(c))
|
|
#define NtfsAllocatePoolNoRaise(a,b) ExAllocatePoolWithTag((a),(b),MODULE_POOL_TAG)
|
|
#define NtfsAllocatePool(a,b) FsRtlAllocatePoolWithTag((a),(b),MODULE_POOL_TAG)
|
|
#define NtfsFreePool(pv) ExFreePool(pv)
|
|
|
|
#else // !DBG
|
|
|
|
//
|
|
// Debugging routines capture the stack backtrace for allocates and frees
|
|
//
|
|
|
|
#define NtfsAllocatePoolWithTagNoRaise(a,b,c) NtfsDebugAllocatePoolWithTagNoRaise((a),(b),(c))
|
|
#define NtfsAllocatePoolWithTag(a,b,c) NtfsDebugAllocatePoolWithTag((a),(b),(c))
|
|
#define NtfsAllocatePoolNoRaise(a,b) NtfsDebugAllocatePoolWithTagNoRaise((a),(b),MODULE_POOL_TAG)
|
|
#define NtfsAllocatePool(a,b) NtfsDebugAllocatePoolWithTag((a),(b),MODULE_POOL_TAG)
|
|
#define NtfsFreePool(pv) NtfsDebugFreePool(pv)
|
|
|
|
PVOID
|
|
NtfsDebugAllocatePoolWithTagNoRaise (
|
|
POOL_TYPE Pool,
|
|
ULONG Length,
|
|
ULONG Tag);
|
|
|
|
PVOID
|
|
NtfsDebugAllocatePoolWithTag (
|
|
POOL_TYPE Pool,
|
|
ULONG Length,
|
|
ULONG Tag);
|
|
|
|
VOID
|
|
NtfsDebugFreePool (
|
|
PVOID pv);
|
|
|
|
VOID
|
|
NtfsDebugHeapDump (
|
|
PUNICODE_STRING UnicodeString );
|
|
|
|
#endif // !DBG
|
|
|
|
//
|
|
// Local character comparison macros that we might want to later move to ntfsproc
|
|
//
|
|
|
|
#define IsCharZero(C) (((C) & 0x000000ff) == 0x00000000)
|
|
#define IsCharMinus1(C) (((C) & 0x000000ff) == 0x000000ff)
|
|
#define IsCharLtrZero(C) (((C) & 0x00000080) == 0x00000080)
|
|
#define IsCharGtrZero(C) (!IsCharLtrZero(C) && !IsCharZero(C))
|
|
|
|
//
|
|
// The following two macro are used to find the first byte to really store
|
|
// in the mapping pairs. They take as input a pointer to the LargeInteger we are
|
|
// trying to store and a pointer to a character pointer. The character pointer
|
|
// on return points to the first byte that we need to output. That's we skip
|
|
// over the high order 0x00 or 0xff bytes.
|
|
//
|
|
|
|
typedef struct _SHORT2 {
|
|
USHORT LowPart;
|
|
USHORT HighPart;
|
|
} SHORT2, *PSHORT2;
|
|
|
|
typedef struct _CHAR2 {
|
|
UCHAR LowPart;
|
|
UCHAR HighPart;
|
|
} CHAR2, *PCHAR2;
|
|
|
|
#define GetPositiveByte(LI,CP) { \
|
|
*(CP) = (PCHAR)(LI); \
|
|
if ((LI)->HighPart != 0) { *(CP) += 4; } \
|
|
if (((PSHORT2)(*(CP)))->HighPart != 0) { *(CP) += 2; } \
|
|
if (((PCHAR2)(*(CP)))->HighPart != 0) { *(CP) += 1; } \
|
|
if (IsCharLtrZero(*(*CP))) { *(CP) += 1; } \
|
|
}
|
|
|
|
#define GetNegativeByte(LI,CP) { \
|
|
*(CP) = (PCHAR)(LI); \
|
|
if ((LI)->HighPart != 0xffffffff) { *(CP) += 4; } \
|
|
if (((PSHORT2)(*(CP)))->HighPart != 0xffff) { *(CP) += 2; } \
|
|
if (((PCHAR2)(*(CP)))->HighPart != 0xff) { *(CP) += 1; } \
|
|
if (!IsCharLtrZero(*(*CP))) { *(CP) += 1; } \
|
|
}
|
|
|
|
|
|
//
|
|
// Flag macros
|
|
//
|
|
// ULONG
|
|
// FlagOn (
|
|
// IN ULONG Flags,
|
|
// IN ULONG SingleFlag
|
|
// );
|
|
//
|
|
// BOOLEAN
|
|
// BooleanFlagOn (
|
|
// IN ULONG Flags,
|
|
// IN ULONG SingleFlag
|
|
// );
|
|
//
|
|
// VOID
|
|
// SetFlag (
|
|
// IN ULONG Flags,
|
|
// IN ULONG SingleFlag
|
|
// );
|
|
//
|
|
// VOID
|
|
// ClearFlag (
|
|
// IN ULONG Flags,
|
|
// IN ULONG SingleFlag
|
|
// );
|
|
//
|
|
|
|
#ifdef KDEXTMODE
|
|
|
|
#ifndef FlagOn
|
|
#define FlagOn(F,SF) ( \
|
|
(((F) & (SF))) \
|
|
)
|
|
#endif
|
|
|
|
#endif
|
|
|
|
//#ifndef BooleanFlagOn
|
|
//#define BooleanFlagOn(F,SF) ( \
|
|
// (BOOLEAN)(((F) & (SF)) != 0) \
|
|
//)
|
|
//#endif
|
|
|
|
//#ifndef SetFlag
|
|
//#define SetFlag(F,SF) { \
|
|
// (F) |= (SF); \
|
|
//}
|
|
//#endif
|
|
|
|
//#ifndef ClearFlag
|
|
//#define ClearFlag(F,SF) { \
|
|
// (F) &= ~(SF); \
|
|
//}
|
|
//#endif
|
|
|
|
|
|
|
|
//
|
|
// The following two macro are used by the Fsd/Fsp exception handlers to
|
|
// process an exception. The first macro is the exception filter used in the
|
|
// Fsd/Fsp to decide if an exception should be handled at this level.
|
|
// The second macro decides if the exception is to be finished off by
|
|
// completing the IRP, and cleaning up the Irp Context, or if we should
|
|
// bugcheck. Exception values such as STATUS_FILE_INVALID (raised by
|
|
// VerfySup.c) cause us to complete the Irp and cleanup, while exceptions
|
|
// such as accvio cause us to bugcheck.
|
|
//
|
|
// The basic structure for fsd/fsp exception handling is as follows:
|
|
//
|
|
// NtfsFsdXxx(..)
|
|
// {
|
|
// try {
|
|
//
|
|
// ..
|
|
//
|
|
// } except(NtfsExceptionFilter( IrpContext, GetExceptionRecord() )) {
|
|
//
|
|
// Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() );
|
|
// }
|
|
//
|
|
// Return Status;
|
|
// }
|
|
//
|
|
// To explicitly raise an exception that we expect, such as
|
|
// STATUS_FILE_INVALID, use the below macro NtfsRaiseStatus). To raise a
|
|
// status from an unknown origin (such as CcFlushCache()), use the macro
|
|
// NtfsNormalizeAndRaiseStatus. This will raise the status if it is expected,
|
|
// or raise STATUS_UNEXPECTED_IO_ERROR if it is not.
|
|
//
|
|
// Note that when using these two macros, the original status is placed in
|
|
// IrpContext->ExceptionStatus, signaling NtfsExceptionFilter and
|
|
// NtfsProcessException that the status we actually raise is by definition
|
|
// expected.
|
|
//
|
|
|
|
VOID
|
|
NtfsCorruptionBreakPointTest (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN ULONG ExceptionCode
|
|
);
|
|
|
|
LONG
|
|
NtfsExceptionFilter (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PEXCEPTION_POINTERS ExceptionPointer
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsProcessException (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN NTSTATUS ExceptionCode
|
|
);
|
|
|
|
VOID
|
|
DECLSPEC_NORETURN
|
|
NtfsRaiseStatus (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN NTSTATUS Status,
|
|
IN PFILE_REFERENCE FileReference OPTIONAL,
|
|
IN PFCB Fcb OPTIONAL
|
|
);
|
|
|
|
ULONG
|
|
NtfsRaiseStatusFunction (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN NTSTATUS Status
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// NtfsNormalAndRaiseStatus (
|
|
// IN PRIP_CONTEXT IrpContext,
|
|
// IN NT_STATUS Status
|
|
// IN NT_STATUS NormalStatus
|
|
// );
|
|
//
|
|
|
|
#define NtfsNormalizeAndRaiseStatus(IC,STAT,NOR_STAT) { \
|
|
(IC)->ExceptionStatus = (STAT); \
|
|
ExRaiseStatus(FsRtlNormalizeNtstatus((STAT),NOR_STAT)); \
|
|
}
|
|
|
|
//
|
|
// Informational popup routine.
|
|
//
|
|
|
|
VOID
|
|
NtfsRaiseInformationHardError (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN NTSTATUS Status,
|
|
IN PFILE_REFERENCE FileReference OPTIONAL,
|
|
IN PFCB Fcb OPTIONAL
|
|
);
|
|
|
|
|
|
//
|
|
// Allocation support routines, implemented in AllocSup.c
|
|
//
|
|
// These routines are for querying, allocating and truncating clusters
|
|
// for individual data streams.
|
|
//
|
|
|
|
//
|
|
// Syscache debugging support - Main current define these are triggered on is
|
|
// SYSCACHE_DEBUG
|
|
//
|
|
|
|
#if (defined(NTFS_RWCMP_TRACE) || defined(SYSCACHE) || defined(NTFS_RWC_DEBUG) || defined(SYSCACHE_DEBUG) || defined(SYSCACHE_DEBUG_ALLOC))
|
|
|
|
BOOLEAN
|
|
FsRtlIsSyscacheFile (
|
|
IN PFILE_OBJECT FileObject
|
|
);
|
|
|
|
//
|
|
// Depreciated verification routine leftover from tomm's original debugging code
|
|
//
|
|
|
|
VOID
|
|
FsRtlVerifySyscacheData (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PVOID Buffer,
|
|
IN ULONG Length,
|
|
IN ULONG Offset
|
|
);
|
|
|
|
ULONG
|
|
FsRtlLogSyscacheEvent (
|
|
IN PSCB Scb,
|
|
IN ULONG Event,
|
|
IN ULONG Flags,
|
|
IN LONGLONG Start,
|
|
IN LONGLONG Range,
|
|
IN LONGLONG Result
|
|
);
|
|
|
|
VOID
|
|
FsRtlUpdateSyscacheEvent (
|
|
IN PSCB Scb,
|
|
IN ULONG EntryNumber,
|
|
IN LONGLONG Result,
|
|
IN ULONG NewFlag
|
|
);
|
|
|
|
#define ScbIsBeingLogged( S ) (((S)->SyscacheLogEntryCount != 0) && (NtfsSyscacheLogSet[(S)->LogSetNumber].Scb == (S)))
|
|
|
|
#define FSCTL_ENABLE_SYSCACHE CTL_CODE( FILE_DEVICE_FILE_SYSTEM, 0x4545, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA )
|
|
|
|
#endif
|
|
|
|
//
|
|
// The following routine takes an Vbo and returns the lbo and size of
|
|
// the run corresponding to the Vbo. It function result is TRUE if
|
|
// the Vbo has a valid Lbo mapping and FALSE otherwise.
|
|
//
|
|
|
|
ULONG
|
|
NtfsPreloadAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PSCB Scb,
|
|
IN VCN StartingVcn,
|
|
IN VCN EndingVcn
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsLookupAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PSCB Scb,
|
|
IN VCN Vcn,
|
|
OUT PLCN Lcn,
|
|
OUT PLONGLONG ClusterCount,
|
|
OUT PVOID *RangePtr OPTIONAL,
|
|
OUT PULONG RunIndex OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsIsRangeAllocated (
|
|
IN PSCB Scb,
|
|
IN VCN StartVcn,
|
|
IN VCN FinalCluster,
|
|
IN BOOLEAN RoundToSparseUnit,
|
|
OUT PLONGLONG ClusterCount
|
|
);
|
|
|
|
//
|
|
// The following two routines modify the allocation of a data stream
|
|
// represented by an Scb.
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsAllocateAttribute (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
|
|
IN PUNICODE_STRING AttributeName OPTIONAL,
|
|
IN USHORT AttributeFlags,
|
|
IN BOOLEAN AllocateAll,
|
|
IN BOOLEAN LogIt,
|
|
IN LONGLONG Size,
|
|
IN PATTRIBUTE_ENUMERATION_CONTEXT NewLocation OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsAddAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_OBJECT FileObject OPTIONAL,
|
|
IN OUT PSCB Scb,
|
|
IN VCN StartingVcn,
|
|
IN LONGLONG ClusterCount,
|
|
IN LOGICAL AskForMore,
|
|
IN OUT PCCB CcbForWriteExtend OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsAddSparseAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_OBJECT FileObject OPTIONAL,
|
|
IN OUT PSCB Scb,
|
|
IN LONGLONG StartingOffset,
|
|
IN LONGLONG ByteCount
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_OBJECT FileObject OPTIONAL,
|
|
IN OUT PSCB Scb,
|
|
IN VCN StartingVcn,
|
|
IN VCN EndingVcn,
|
|
IN BOOLEAN LogIt,
|
|
IN BOOLEAN BreakupAllowed
|
|
);
|
|
|
|
VOID
|
|
NtfsReallocateRange (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PSCB Scb,
|
|
IN VCN DeleteVcn,
|
|
IN LONGLONG DeleteCount,
|
|
IN VCN AllocateVcn,
|
|
IN LONGLONG AllocateCount,
|
|
IN PLCN TargetLcn OPTIONAL
|
|
);
|
|
|
|
//
|
|
// Routines for Mcb to Mapping Pairs operations
|
|
//
|
|
|
|
ULONG
|
|
NtfsGetSizeForMappingPairs (
|
|
IN PNTFS_MCB Mcb,
|
|
IN ULONG BytesAvailable,
|
|
IN VCN LowestVcn,
|
|
IN PVCN StopOnVcn OPTIONAL,
|
|
OUT PVCN StoppedOnVcn
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsBuildMappingPairs (
|
|
IN PNTFS_MCB Mcb,
|
|
IN VCN LowestVcn,
|
|
IN OUT PVCN HighestVcn,
|
|
OUT PCHAR MappingPairs
|
|
);
|
|
|
|
VCN
|
|
NtfsGetHighestVcn (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN VCN LowestVcn,
|
|
IN PCHAR EndOfMappingPairs,
|
|
IN PCHAR MappingPairs
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsReserveClusters (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PSCB Scb,
|
|
IN LONGLONG FileOffset,
|
|
IN ULONG ByteCount
|
|
);
|
|
|
|
VOID
|
|
NtfsFreeReservedClusters (
|
|
IN PSCB Scb,
|
|
IN LONGLONG FileOffset,
|
|
IN ULONG ByteCount
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCheckForReservedClusters (
|
|
IN PSCB Scb,
|
|
IN LONGLONG StartingVcn,
|
|
IN OUT PLONGLONG ClusterCount
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteReservedBitmap (
|
|
IN PSCB Scb
|
|
);
|
|
|
|
|
|
//
|
|
// Attribute lookup routines, implemented in AttrSup.c
|
|
//
|
|
|
|
//
|
|
// This macro detects if we are enumerating through base or external
|
|
// attributes, and calls the appropriate function.
|
|
//
|
|
// BOOLEAN
|
|
// LookupNextAttribute (
|
|
// IN PRIP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN ATTRIBUTE_TYPE_CODE Code,
|
|
// IN PUNICODE_STRING Name OPTIONAL,
|
|
// IN BOOLEAN IgnoreCase,
|
|
// IN PVOID Value OPTIONAL,
|
|
// IN ULONG ValueLength,
|
|
// IN PVCN Vcn OPTIONAL,
|
|
// IN PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// );
|
|
//
|
|
|
|
#define LookupNextAttribute(IRPCTXT,FCB,CODE,NAME,IC,VALUE,LENGTH,V,CONTEXT) \
|
|
( (CONTEXT)->AttributeList.Bcb == NULL \
|
|
? NtfsLookupInFileRecord( (IRPCTXT), \
|
|
(FCB), \
|
|
NULL, \
|
|
(CODE), \
|
|
(NAME), \
|
|
(V), \
|
|
(IC), \
|
|
(VALUE), \
|
|
(LENGTH), \
|
|
(CONTEXT)) \
|
|
: NtfsLookupExternalAttribute((IRPCTXT), \
|
|
(FCB), \
|
|
(CODE), \
|
|
(NAME), \
|
|
(V), \
|
|
(IC), \
|
|
(VALUE), \
|
|
(LENGTH), \
|
|
(CONTEXT)) )
|
|
|
|
BOOLEAN
|
|
NtfsLookupExternalAttribute (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN ATTRIBUTE_TYPE_CODE QueriedTypeCode,
|
|
IN PCUNICODE_STRING QueriedName OPTIONAL,
|
|
IN PVCN Vcn OPTIONAL,
|
|
IN BOOLEAN IgnoreCase,
|
|
IN PVOID QueriedValue OPTIONAL,
|
|
IN ULONG QueriedValueLength,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// The following two routines do lookups based on the attribute definitions.
|
|
//
|
|
|
|
ATTRIBUTE_TYPE_CODE
|
|
NtfsGetAttributeTypeCode (
|
|
IN PVCB Vcb,
|
|
IN PUNICODE_STRING AttributeTypeName
|
|
);
|
|
|
|
|
|
//
|
|
// PATTRIBUTE_DEFINITION_COLUMNS
|
|
// NtfsGetAttributeDefinition (
|
|
// IN PVCB Vcb,
|
|
// IN ATTRIBUTE_TYPE_CODE AttributeTypeCode
|
|
// )
|
|
//
|
|
|
|
#define NtfsGetAttributeDefinition(Vcb,AttributeTypeCode) \
|
|
(&Vcb->AttributeDefinitions[(AttributeTypeCode / 0x10) - 1])
|
|
|
|
//
|
|
// This routine looks up the attribute uniquely-qualified by the specified
|
|
// Attribute Code and case-sensitive name. The attribute may not be unique
|
|
// if IgnoreCase is specified.
|
|
//
|
|
|
|
|
|
BOOLEAN
|
|
NtfsLookupInFileRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PFILE_REFERENCE BaseFileReference OPTIONAL,
|
|
IN ATTRIBUTE_TYPE_CODE QueriedTypeCode,
|
|
IN PCUNICODE_STRING QueriedName OPTIONAL,
|
|
IN PVCN Vcn OPTIONAL,
|
|
IN BOOLEAN IgnoreCase,
|
|
IN PVOID QueriedValue OPTIONAL,
|
|
IN ULONG QueriedValueLength,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
|
|
//
|
|
// This routine attempts to find the fist occurrence of an attribute with
|
|
// the specified AttributeTypeCode and the specified QueriedName in the
|
|
// specified BaseFileReference. If we find one, its attribute record is
|
|
// pinned and returned.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupAttributeByName (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN PFILE_REFERENCE BaseFileReference,
|
|
// IN ATTRIBUTE_TYPE_CODE QueriedTypeCode,
|
|
// IN PUNICODE_STRING QueriedName OPTIONAL,
|
|
// IN PVCN Vcn OPTIONAL,
|
|
// IN BOOLEAN IgnoreCase,
|
|
// OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
|
|
#define NtfsLookupAttributeByName(IrpContext,Fcb,BaseFileReference,QueriedTypeCode,QueriedName,Vcn,IgnoreCase,Context) \
|
|
NtfsLookupInFileRecord( IrpContext, \
|
|
Fcb, \
|
|
BaseFileReference, \
|
|
QueriedTypeCode, \
|
|
QueriedName, \
|
|
Vcn, \
|
|
IgnoreCase, \
|
|
NULL, \
|
|
0, \
|
|
Context )
|
|
|
|
|
|
//
|
|
// This function continues where the prior left off.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupNextAttributeByName (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN ATTRIBUTE_TYPE_CODE QueriedTypeCode,
|
|
// IN PUNICODE_STRING QueriedName OPTIONAL,
|
|
// IN BOOLEAN IgnoreCase,
|
|
// IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
#define NtfsLookupNextAttributeByName(IrpContext,Fcb,QueriedTypeCode,QueriedName,IgnoreCase,Context) \
|
|
LookupNextAttribute( IrpContext, \
|
|
Fcb, \
|
|
QueriedTypeCode, \
|
|
QueriedName, \
|
|
IgnoreCase, \
|
|
NULL, \
|
|
0, \
|
|
NULL, \
|
|
Context )
|
|
|
|
//
|
|
// The following does a search based on a VCN.
|
|
//
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupNextAttributeByVcn (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN PVCN Vcn OPTIONAL,
|
|
// OUT PATTRIBUTE_ENUMERATION_CONTEXT
|
|
// );
|
|
//
|
|
|
|
#define NtfsLookupNextAttributeByVcn(IC,F,V,C) \
|
|
LookupNextAttribute( (IC), \
|
|
(F), \
|
|
$UNUSED, \
|
|
NULL, \
|
|
FALSE, \
|
|
NULL, \
|
|
FALSE, \
|
|
(V), \
|
|
(C) )
|
|
|
|
//
|
|
// The following routines find the attribute record for a given Scb.
|
|
// And also update the scb from the attribute
|
|
//
|
|
// VOID
|
|
// NtfsLookupAttributeForScb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PSCB Scb,
|
|
// IN PVCN Vcn OPTIONAL,
|
|
// IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
|
|
#define NtfsLookupAttributeForScb(IrpContext,Scb,Vcn,Context) \
|
|
if (!NtfsLookupAttributeByName( IrpContext, \
|
|
Scb->Fcb, \
|
|
&Scb->Fcb->FileReference, \
|
|
Scb->AttributeTypeCode, \
|
|
&Scb->AttributeName, \
|
|
Vcn, \
|
|
FALSE, \
|
|
Context ) && \
|
|
!FlagOn( Scb->ScbState, SCB_STATE_VIEW_INDEX )) { \
|
|
\
|
|
DebugTrace( 0, 0, ("Could not find attribute for Scb @ %08lx\n", Scb )); \
|
|
ASSERTMSG("Could not find attribute for Scb\n", FALSE); \
|
|
NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Scb->Fcb ); \
|
|
}
|
|
|
|
|
|
//
|
|
// This routine looks up and returns the next attribute for a given Scb.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupNextAttributeForScb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PSCB Scb,
|
|
// IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
|
|
#define NtfsLookupNextAttributeForScb(IrpContext,Scb,Context) \
|
|
NtfsLookupNextAttributeByName( IrpContext, \
|
|
Scb->Fcb, \
|
|
Scb->AttributeTypeCode, \
|
|
&Scb->AttributeName, \
|
|
FALSE, \
|
|
Context )
|
|
|
|
VOID
|
|
NtfsUpdateScbFromAttribute (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PSCB Scb,
|
|
IN PATTRIBUTE_RECORD_HEADER AttrHeader OPTIONAL
|
|
);
|
|
|
|
//
|
|
// The following routines deal with the Fcb and the duplicated information field.
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsUpdateFcbInfoFromDisk (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN BOOLEAN LoadSecurity,
|
|
IN OUT PFCB Fcb,
|
|
OUT POLD_SCB_SNAPSHOT UnnamedDataSizes OPTIONAL
|
|
);
|
|
|
|
//
|
|
// These routines looks up the first/next attribute, i.e., they may be used
|
|
// to retrieve all atributes for a file record.
|
|
//
|
|
// If the Bcb in the Found Attribute structure changes in the Next call, then
|
|
// the previous Bcb is autmatically unpinned and the new one pinned.
|
|
//
|
|
|
|
//
|
|
// This routine attempts to find the fist occurrence of an attribute with
|
|
// the specified AttributeTypeCode in the specified BaseFileReference. If we
|
|
// find one, its attribute record is pinned and returned.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupAttribute (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN PFILE_REFERENCE BaseFileReference,
|
|
// OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
|
|
#define NtfsLookupAttribute(IrpContext,Fcb,BaseFileReference,Context) \
|
|
NtfsLookupInFileRecord( IrpContext, \
|
|
Fcb, \
|
|
BaseFileReference, \
|
|
$UNUSED, \
|
|
NULL, \
|
|
NULL, \
|
|
FALSE, \
|
|
NULL, \
|
|
0, \
|
|
Context )
|
|
|
|
//
|
|
// This function continues where the prior left off.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupNextAttribute (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
|
|
#define NtfsLookupNextAttribute(IrpContext,Fcb,Context) \
|
|
LookupNextAttribute( IrpContext, \
|
|
Fcb, \
|
|
$UNUSED, \
|
|
NULL, \
|
|
FALSE, \
|
|
NULL, \
|
|
0, \
|
|
NULL, \
|
|
Context )
|
|
|
|
|
|
//
|
|
// These routines looks up the first/next attribute of the given type code.
|
|
//
|
|
// If the Bcb in the Found Attribute structure changes in the Next call, then
|
|
// the previous Bcb is autmatically unpinned and the new one pinned.
|
|
//
|
|
|
|
|
|
//
|
|
// This routine attempts to find the fist occurrence of an attribute with
|
|
// the specified AttributeTypeCode in the specified BaseFileReference. If we
|
|
// find one, its attribute record is pinned and returned.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupAttributeByCode (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN PFILE_REFERENCE BaseFileReference,
|
|
// IN ATTRIBUTE_TYPE_CODE QueriedTypeCode,
|
|
// OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
|
|
#define NtfsLookupAttributeByCode(IrpContext,Fcb,BaseFileReference,QueriedTypeCode,Context) \
|
|
NtfsLookupInFileRecord( IrpContext, \
|
|
Fcb, \
|
|
BaseFileReference, \
|
|
QueriedTypeCode, \
|
|
NULL, \
|
|
NULL, \
|
|
FALSE, \
|
|
NULL, \
|
|
0, \
|
|
Context )
|
|
|
|
|
|
//
|
|
// This function continues where the prior left off.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupNextAttributeByCode (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN ATTRIBUTE_TYPE_CODE QueriedTypeCode,
|
|
// IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
|
|
#define NtfsLookupNextAttributeByCode(IC,F,CODE,C) \
|
|
LookupNextAttribute( (IC), \
|
|
(F), \
|
|
(CODE), \
|
|
NULL, \
|
|
FALSE, \
|
|
NULL, \
|
|
0, \
|
|
NULL, \
|
|
(C) )
|
|
|
|
//
|
|
// These routines looks up the first/next occurrence of an attribute by its
|
|
// Attribute Code and exact attribute value (consider using RtlCompareMemory).
|
|
// The value contains everything outside of the standard attribute header,
|
|
// so for example, to look up the File Name attribute by value, the caller
|
|
// must form a record with not only the file name in it, but with the
|
|
// ParentDirectory filled in as well. The length should be exact, and not
|
|
// include any unused (such as in DOS_NAME) or reserved characters.
|
|
//
|
|
// If the Bcb changes in the Next call, then the previous Bcb is autmatically
|
|
// unpinned and the new one pinned.
|
|
//
|
|
|
|
|
|
//
|
|
// This routine attempts to find the fist occurrence of an attribute with
|
|
// the specified AttributeTypeCode and the specified QueriedValue in the
|
|
// specified BaseFileReference. If we find one, its attribute record is
|
|
// pinned and returned.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupAttributeByValue (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN PFILE_REFERENCE BaseFileReference,
|
|
// IN ATTRIBUTE_TYPE_CODE QueriedTypeCode,
|
|
// IN PVOID QueriedValue,
|
|
// IN ULONG QueriedValueLength,
|
|
// OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
|
|
#define NtfsLookupAttributeByValue(IrpContext,Fcb,BaseFileReference,QueriedTypeCode,QueriedValue,QueriedValueLength,Context) \
|
|
NtfsLookupInFileRecord( IrpContext, \
|
|
Fcb, \
|
|
BaseFileReference, \
|
|
QueriedTypeCode, \
|
|
NULL, \
|
|
NULL, \
|
|
FALSE, \
|
|
QueriedValue, \
|
|
QueriedValueLength, \
|
|
Context )
|
|
|
|
//
|
|
// This function continues where the prior left off.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsLookupNextAttributeByValue (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN ATTRIBUTE_TYPE_CODE QueriedTypeCode,
|
|
// IN PVOID QueriedValue,
|
|
// IN ULONG QueriedValueLength,
|
|
// IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
// )
|
|
//
|
|
|
|
#define NtfsLookupNextAttributeByValue(IC,F,CODE,V,VL,C) \
|
|
LookupNextAttribute( (IC), \
|
|
(F), \
|
|
(CODE), \
|
|
NULL, \
|
|
FALSE, \
|
|
(V), \
|
|
(VL), \
|
|
(C) )
|
|
|
|
|
|
VOID
|
|
NtfsCleanupAttributeContext(
|
|
IN OUT PIRP_CONTEXT IrpContext,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT AttributeContext
|
|
);
|
|
|
|
//
|
|
//
|
|
//
|
|
// Here are some routines/macros for dealing with Attribute Enumeration
|
|
// Contexts.
|
|
//
|
|
// VOID
|
|
// NtfsInitializeAttributeContext(
|
|
// OUT PATTRIBUTE_ENUMERATION_CONTEXT AttributeContext
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsPinMappedAttribute(
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb,
|
|
// IN OUT PATTRIBUTE_ENUMERATION_CONTEXT AttributeContext
|
|
// );
|
|
//
|
|
// PATTRIBUTE_RECORD_HEADER
|
|
// NtfsFoundAttribute(
|
|
// IN PATTRIBUTE_ENUMERATION_CONTEXT AttributeContext
|
|
// );
|
|
//
|
|
// PBCB
|
|
// NtfsFoundBcb(
|
|
// IN PATTRIBUTE_ENUMERATION_CONTEXT AttributeContext
|
|
// );
|
|
//
|
|
// PFILE_RECORD
|
|
// NtfsContainingFileRecord (
|
|
// IN PATTRIBUTE_ENUMERATION_CONTEXT AttributeContext
|
|
// );
|
|
//
|
|
// LONGLONG
|
|
// NtfsMftOffset (
|
|
// IN PATTRIBUTE_ENUMERATION_CONTEXT AttributeContext
|
|
// );
|
|
//
|
|
|
|
#define NtfsInitializeAttributeContext(CTX) { \
|
|
RtlZeroMemory( (CTX), sizeof(ATTRIBUTE_ENUMERATION_CONTEXT) ); \
|
|
}
|
|
|
|
#define NtfsPinMappedAttribute(IC,V,CTX) { \
|
|
NtfsPinMappedData( (IC), \
|
|
(V)->MftScb, \
|
|
(CTX)->FoundAttribute.MftFileOffset, \
|
|
(V)->BytesPerFileRecordSegment, \
|
|
&(CTX)->FoundAttribute.Bcb ); \
|
|
}
|
|
|
|
#define NtfsFoundAttribute(CTX) ( \
|
|
(CTX)->FoundAttribute.Attribute \
|
|
)
|
|
|
|
#define NtfsFoundBcb(CTX) ( \
|
|
(CTX)->FoundAttribute.Bcb \
|
|
)
|
|
|
|
#define NtfsContainingFileRecord(CTX) ( \
|
|
(CTX)->FoundAttribute.FileRecord \
|
|
)
|
|
|
|
#define NtfsMftOffset(CTX) ( \
|
|
(CTX)->FoundAttribute.MftFileOffset \
|
|
)
|
|
|
|
//
|
|
// This routine returns whether an attribute is resident or not.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsIsAttributeResident (
|
|
// IN PATTRIBUTE_RECORD_HEADER Attribute
|
|
// );
|
|
//
|
|
// PVOID
|
|
// NtfsAttributeValue (
|
|
// IN PATTRIBUTE_RECORD_HEADER Attribute
|
|
// );
|
|
//
|
|
|
|
#define NtfsIsAttributeResident(ATTR) ( \
|
|
((ATTR)->FormCode == RESIDENT_FORM) \
|
|
)
|
|
|
|
#define NtfsAttributeValue(ATTR) ( \
|
|
((PCHAR)(ATTR) + (ULONG)(ATTR)->Form.Resident.ValueOffset) \
|
|
)
|
|
|
|
//
|
|
// This routine modifies the valid data length and file size on disk for
|
|
// a given Scb.
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsWriteFileSizes (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PLONGLONG ValidDataLength,
|
|
IN BOOLEAN AdvanceOnly,
|
|
IN BOOLEAN LogIt,
|
|
IN BOOLEAN RollbackMemStructures
|
|
);
|
|
|
|
//
|
|
// This routine updates the standard information attribute from the
|
|
// information in the Fcb.
|
|
//
|
|
|
|
VOID
|
|
NtfsUpdateStandardInformation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
//
|
|
// This routine grows and updates the standard information attribute from
|
|
// the information in the Fcb.
|
|
//
|
|
|
|
VOID
|
|
NtfsGrowStandardInformation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
//
|
|
// Attribute FILE_NAME routines. These routines deal with filename attributes.
|
|
//
|
|
|
|
// VOID
|
|
// NtfsBuildFileNameAttribute (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFILE_REFERENCE ParentDirectory,
|
|
// IN UNICODE_STRING FileName,
|
|
// IN UCHAR Flags,
|
|
// OUT PFILE_NAME FileNameValue
|
|
// );
|
|
//
|
|
|
|
#define NtfsBuildFileNameAttribute(IC,PD,FN,FL,PFNA) { \
|
|
(PFNA)->ParentDirectory = *(PD); \
|
|
(PFNA)->FileNameLength = (UCHAR)((FN).Length >> 1); \
|
|
(PFNA)->Flags = FL; \
|
|
RtlMoveMemory( (PFNA)->FileName, (FN).Buffer, (ULONG)(FN).Length ); \
|
|
}
|
|
|
|
BOOLEAN
|
|
NtfsLookupEntry (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB ParentScb,
|
|
IN BOOLEAN IgnoreCase,
|
|
IN OUT PUNICODE_STRING Name,
|
|
IN OUT PFILE_NAME *FileNameAttr,
|
|
IN OUT PUSHORT FileNameAttrLength,
|
|
OUT PQUICK_INDEX QuickIndex OPTIONAL,
|
|
OUT PINDEX_ENTRY *IndexEntry,
|
|
OUT PBCB *IndexEntryBcb,
|
|
OUT PINDEX_CONTEXT IndexContext OPTIONAL
|
|
);
|
|
|
|
//
|
|
// Macro to decide when to create an attribute resident.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsShouldAttributeBeResident (
|
|
// IN PVCB Vcb,
|
|
// IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
// IN ULONG Size
|
|
// );
|
|
//
|
|
|
|
#define RS(S) ((S) + SIZEOF_RESIDENT_ATTRIBUTE_HEADER)
|
|
|
|
#define NtfsShouldAttributeBeResident(VC,FR,S) ( \
|
|
(BOOLEAN)((RS(S) <= ((FR)->BytesAvailable - (FR)->FirstFreeByte)) || \
|
|
(RS(S) < (VC)->BigEnoughToMove)) \
|
|
)
|
|
|
|
//
|
|
// Attribute creation/modification routines
|
|
//
|
|
// These three routines do *not* presuppose either the Resident or Nonresident
|
|
// form, with the single exception that if the attribute is indexed, then
|
|
// it must be Resident.
|
|
//
|
|
// NtfsMapAttributeValue and NtfsChangeAttributeValue implement transparent
|
|
// access to small to medium sized attributes (such as $ACL and $EA), and
|
|
// work whether the attribute is resident or nonresident. The design target
|
|
// is 0-64KB in size. Attributes larger than 256KB (or more accurrately,
|
|
// whatever the virtual mapping granularity is in the Cache Manager) will not
|
|
// work correctly.
|
|
//
|
|
|
|
VOID
|
|
NtfsCreateAttributeWithValue (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
|
|
IN PUNICODE_STRING AttributeName OPTIONAL,
|
|
IN PVOID Value OPTIONAL,
|
|
IN ULONG ValueLength,
|
|
IN USHORT AttributeFlags,
|
|
IN PFILE_REFERENCE WhereIndexed OPTIONAL,
|
|
IN BOOLEAN LogIt,
|
|
OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
NtfsMapAttributeValue (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
OUT PVOID *Buffer,
|
|
OUT PULONG Length,
|
|
OUT PBCB *Bcb,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
NtfsChangeAttributeValue (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN ULONG ValueOffset,
|
|
IN PVOID Value OPTIONAL,
|
|
IN ULONG ValueLength,
|
|
IN BOOLEAN SetNewLength,
|
|
IN BOOLEAN LogNonresidentToo,
|
|
IN BOOLEAN CreateSectionUnderway,
|
|
IN BOOLEAN PreserveContext,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
NtfsConvertToNonresident (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN OUT PATTRIBUTE_RECORD_HEADER Attribute,
|
|
IN BOOLEAN CreateSectionUnderway,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context OPTIONAL
|
|
);
|
|
|
|
#define DELETE_LOG_OPERATION 0x00000001
|
|
#define DELETE_RELEASE_FILE_RECORD 0x00000002
|
|
#define DELETE_RELEASE_ALLOCATION 0x00000004
|
|
|
|
VOID
|
|
NtfsDeleteAttributeRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN ULONG Flags,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteAllocationFromRecord (
|
|
PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PATTRIBUTE_ENUMERATION_CONTEXT Context,
|
|
IN BOOLEAN BreakupAllowed,
|
|
IN BOOLEAN LogIt
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsChangeAttributeSize (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN ULONG Length,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
NtfsAddToAttributeList (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN MFT_SEGMENT_REFERENCE SegmentReference,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteFromAttributeList (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsRewriteMftMapping (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsSetTotalAllocatedField (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN USHORT TotalAllocatedNeeded
|
|
);
|
|
|
|
VOID
|
|
NtfsSetSparseStream (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB ParentScb OPTIONAL,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsZeroRangeInStream (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_OBJECT FileObject OPTIONAL,
|
|
IN PSCB Scb,
|
|
IN PLONGLONG StartingOffset,
|
|
IN LONGLONG FinalZero
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsModifyAttributeFlags (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN USHORT NewAttributeFlags
|
|
);
|
|
|
|
PFCB
|
|
NtfsInitializeFileInExtendDirectory (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PCUNICODE_STRING FileName,
|
|
IN BOOLEAN ViewIndex,
|
|
IN ULONG CreateIfNotExist
|
|
);
|
|
|
|
//
|
|
// Use common routines to fill the common query buffers.
|
|
//
|
|
|
|
VOID
|
|
NtfsFillBasicInfo (
|
|
OUT PFILE_BASIC_INFORMATION Buffer,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
VOID
|
|
NtfsFillStandardInfo (
|
|
OUT PFILE_STANDARD_INFORMATION Buffer,
|
|
IN PSCB Scb,
|
|
IN PCCB Ccb OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsFillNetworkOpenInfo (
|
|
OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
//
|
|
// The following three routines dealing with allocation are to be
|
|
// called by allocsup.c only. Other software must call the routines
|
|
// in allocsup.c
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsCreateAttributeWithAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
|
|
IN PUNICODE_STRING AttributeName OPTIONAL,
|
|
IN USHORT AttributeFlags,
|
|
IN BOOLEAN LogIt,
|
|
IN BOOLEAN UseContext,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
NtfsAddAttributeAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context,
|
|
IN PVCN StartingVcn OPTIONAL,
|
|
IN PVCN ClusterCount OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteAttributeAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN BOOLEAN LogIt,
|
|
IN PVCN StopOnVcn,
|
|
IN OUT PATTRIBUTE_ENUMERATION_CONTEXT Context,
|
|
IN BOOLEAN TruncateToVcn
|
|
);
|
|
|
|
//
|
|
// To delete a file, you must first ask if it is deleteable from the ParentScb
|
|
// used to get there for your caller, and then you can delete it if it is.
|
|
//
|
|
|
|
//
|
|
// BOOLEAN
|
|
// NtfsIsLinkDeleteable (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// OUT PBOOLEAN NonEmptyIndex,
|
|
// OUT PBOOLEAN LastLink
|
|
// );
|
|
//
|
|
|
|
#define NtfsIsLinkDeleteable(IC,FC,NEI,LL) ((BOOLEAN) \
|
|
(((*(LL) = ((BOOLEAN) (FC)->LinkCount == 1)), (FC)->LinkCount > 1) || \
|
|
(NtfsIsFileDeleteable( (IC), (FC), (NEI) ))) \
|
|
)
|
|
|
|
BOOLEAN
|
|
NtfsIsFileDeleteable (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
OUT PBOOLEAN NonEmptyIndex
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteFile (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB ParentScb,
|
|
IN OUT PBOOLEAN AcquiredParentScb,
|
|
IN OUT PNAME_PAIR NamePair OPTIONAL,
|
|
IN OUT PNTFS_TUNNELED_DATA TunneledData OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsPrepareForUpdateDuplicate (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN OUT PLCB *Lcb,
|
|
IN OUT PSCB *ParentScb,
|
|
IN BOOLEAN AcquireShared
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateDuplicateInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PLCB Lcb OPTIONAL,
|
|
IN PSCB ParentScb OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateLcbDuplicateInfo (
|
|
IN PFCB Fcb,
|
|
IN PLCB Lcb
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateFcb (
|
|
IN PFCB Fcb,
|
|
IN ULONG ChangeFlags
|
|
);
|
|
|
|
//
|
|
// The following routines add and remove links. They also update the name
|
|
// flags in particular links.
|
|
//
|
|
|
|
VOID
|
|
NtfsAddLink (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN BOOLEAN CreatePrimaryLink,
|
|
IN PSCB ParentScb,
|
|
IN PFCB Fcb,
|
|
IN PFILE_NAME FileNameAttr,
|
|
IN PBOOLEAN LogIt OPTIONAL,
|
|
OUT PUCHAR FileNameFlags,
|
|
OUT PQUICK_INDEX QuickIndex OPTIONAL,
|
|
IN PNAME_PAIR NamePair OPTIONAL,
|
|
IN PINDEX_CONTEXT IndexContext OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsRemoveLink (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB ParentScb,
|
|
IN UNICODE_STRING LinkName,
|
|
IN OUT PNAME_PAIR NamePair OPTIONAL,
|
|
IN OUT PNTFS_TUNNELED_DATA TunneledData OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsRemoveLinkViaFlags (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB Scb,
|
|
IN UCHAR FileNameFlags,
|
|
IN OUT PNAME_PAIR NamePair OPTIONAL,
|
|
OUT PUNICODE_STRING FileName OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateFileNameFlags (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB ParentScb,
|
|
IN UCHAR FileNameFlags,
|
|
IN PFILE_NAME FileNameLink
|
|
);
|
|
|
|
//
|
|
// These routines are intended for low-level attribute access, such as within
|
|
// attrsup, or for applying update operations from the log during restart.
|
|
//
|
|
|
|
VOID
|
|
NtfsRestartInsertAttribute (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN ULONG RecordOffset,
|
|
IN PATTRIBUTE_RECORD_HEADER Attribute,
|
|
IN PUNICODE_STRING AttributeName OPTIONAL,
|
|
IN PVOID ValueOrMappingPairs OPTIONAL,
|
|
IN ULONG Length
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartRemoveAttribute (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN ULONG RecordOffset
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartChangeAttributeSize (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN PATTRIBUTE_RECORD_HEADER Attribute,
|
|
IN ULONG NewRecordLength
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartChangeValue (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN ULONG RecordOffset,
|
|
IN ULONG AttributeOffset,
|
|
IN PVOID Data OPTIONAL,
|
|
IN ULONG Length,
|
|
IN BOOLEAN SetNewLength
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartChangeMapping (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN ULONG RecordOffset,
|
|
IN ULONG AttributeOffset,
|
|
IN PVOID Data,
|
|
IN ULONG Length
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartWriteEndOfFileRecord (
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN PATTRIBUTE_RECORD_HEADER OldAttribute,
|
|
IN PATTRIBUTE_RECORD_HEADER NewAttributes,
|
|
IN ULONG SizeOfNewAttributes
|
|
);
|
|
|
|
|
|
//
|
|
// Bitmap support routines. Implemented in BitmpSup.c
|
|
//
|
|
|
|
//
|
|
// The following routines are used for allocating and deallocating clusters
|
|
// on the disk. The first routine initializes the allocation support
|
|
// routines and must be called for each newly mounted/verified volume.
|
|
// The next two routines allocate and deallocate clusters via Mcbs.
|
|
// The last three routines are simple query routines.
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeClusterAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsAllocateClusters (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN OUT PSCB Scb,
|
|
IN VCN StartingVcn,
|
|
IN BOOLEAN AllocateAll,
|
|
IN LONGLONG ClusterCount,
|
|
IN PLCN TargetLcn OPTIONAL,
|
|
IN OUT PLONGLONG DesiredClusterCount
|
|
);
|
|
|
|
VOID
|
|
NtfsAddBadCluster (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN LCN Lcn
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsDeallocateClusters (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PSCB Scb,
|
|
IN VCN StartingVcn,
|
|
IN VCN EndingVcn,
|
|
OUT PLONGLONG TotalAllocated OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsPreAllocateClusters (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN LCN StartingLcn,
|
|
IN LONGLONG ClusterCount,
|
|
OUT PBOOLEAN AcquiredBitmap,
|
|
OUT PBOOLEAN AcquiredMft
|
|
);
|
|
|
|
VOID
|
|
NtfsCleanupClusterAllocationHints (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PNTFS_MCB Mcb
|
|
);
|
|
|
|
VOID
|
|
NtfsScanEntireBitmap (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN LOGICAL CachedRunsOnly
|
|
);
|
|
|
|
VOID
|
|
NtfsModifyBitsInBitmap (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN LONGLONG FirstBit,
|
|
IN LONGLONG BeyondFinalBit,
|
|
IN ULONG RedoOperation,
|
|
IN ULONG UndoOperation
|
|
);
|
|
|
|
typedef enum _NTFS_RUN_STATE {
|
|
RunStateUnknown = 1,
|
|
RunStateFree,
|
|
RunStateAllocated
|
|
} NTFS_RUN_STATE;
|
|
typedef NTFS_RUN_STATE *PNTFS_RUN_STATE;
|
|
|
|
BOOLEAN
|
|
NtfsAddCachedRun (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN LCN StartingLcn,
|
|
IN LONGLONG ClusterCount,
|
|
IN NTFS_RUN_STATE RunState
|
|
);
|
|
|
|
//
|
|
// The following two routines are called at Restart to make bitmap
|
|
// operations in the volume bitmap recoverable.
|
|
//
|
|
|
|
VOID
|
|
NtfsRestartSetBitsInBitMap (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PRTL_BITMAP Bitmap,
|
|
IN ULONG BitMapOffset,
|
|
IN ULONG NumberOfBits
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartClearBitsInBitMap (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PRTL_BITMAP Bitmap,
|
|
IN ULONG BitMapOffset,
|
|
IN ULONG NumberOfBits
|
|
);
|
|
|
|
//
|
|
// The following routines are for allocating and deallocating records
|
|
// based on a bitmap attribute (e.g., allocating mft file records based on
|
|
// the bitmap attribute of the mft). If necessary the routines will
|
|
// also extend/truncate the data and bitmap attributes to satisfy the
|
|
// operation.
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeRecordAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB DataScb,
|
|
IN PATTRIBUTE_ENUMERATION_CONTEXT BitmapAttribute,
|
|
IN ULONG BytesPerRecord,
|
|
IN ULONG ExtendGranularity, // In terms of records
|
|
IN ULONG TruncateGranularity, // In terms of records
|
|
IN OUT PRECORD_ALLOCATION_CONTEXT RecordAllocationContext
|
|
);
|
|
|
|
VOID
|
|
NtfsUninitializeRecordAllocation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PRECORD_ALLOCATION_CONTEXT RecordAllocationContext
|
|
);
|
|
|
|
ULONG
|
|
NtfsAllocateRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PRECORD_ALLOCATION_CONTEXT RecordAllocationContext,
|
|
IN PATTRIBUTE_ENUMERATION_CONTEXT BitmapAttribute
|
|
);
|
|
|
|
VOID
|
|
NtfsDeallocateRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PRECORD_ALLOCATION_CONTEXT RecordAllocationContext,
|
|
IN ULONG Index,
|
|
IN PATTRIBUTE_ENUMERATION_CONTEXT BitmapAttribute
|
|
);
|
|
|
|
VOID
|
|
NtfsReserveMftRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PVCB Vcb,
|
|
IN PATTRIBUTE_ENUMERATION_CONTEXT BitmapAttribute
|
|
);
|
|
|
|
ULONG
|
|
NtfsAllocateMftReservedRecord (
|
|
IN OUT PIRP_CONTEXT IrpContext,
|
|
IN OUT PVCB Vcb,
|
|
IN PATTRIBUTE_ENUMERATION_CONTEXT BitmapAttribute
|
|
);
|
|
|
|
VOID
|
|
NtfsDeallocateRecordsComplete (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsIsRecordAllocated (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PRECORD_ALLOCATION_CONTEXT RecordAllocationContext,
|
|
IN ULONG Index,
|
|
IN PATTRIBUTE_ENUMERATION_CONTEXT BitmapAttribute
|
|
);
|
|
|
|
VOID
|
|
NtfsScanMftBitmap (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PVCB Vcb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCreateMftHole (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFindMftFreeTail (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
OUT PLONGLONG FileOffset
|
|
);
|
|
|
|
//
|
|
// Routines to handle the cached runs.
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeCachedRuns (
|
|
IN PNTFS_CACHED_RUNS CachedRuns
|
|
);
|
|
|
|
VOID
|
|
NtfsReinitializeCachedRuns (
|
|
IN PNTFS_CACHED_RUNS CachedRuns
|
|
);
|
|
|
|
VOID
|
|
NtfsUninitializeCachedRuns (
|
|
IN PNTFS_CACHED_RUNS CachedRuns
|
|
);
|
|
|
|
|
|
//
|
|
// Buffer control routines for data caching using internal attribute
|
|
// streams implemented in CacheSup.c
|
|
//
|
|
|
|
#define NtfsCreateInternalAttributeStream(IC,S,U,NM) { \
|
|
NtfsCreateInternalStreamCommon((IC),(S),(U),FALSE,(NM)); \
|
|
}
|
|
|
|
#define NtfsCreateInternalCompressedStream(IC,S,U,NM) { \
|
|
NtfsCreateInternalStreamCommon((IC),(S),(U),TRUE,(NM)); \
|
|
}
|
|
|
|
#define NtfsClearInternalFilename(_FileObject) { \
|
|
(_FileObject)->FileName.MaximumLength = 0; \
|
|
(_FileObject)->FileName.Length = 0; \
|
|
(_FileObject)->FileName.Buffer = NULL; \
|
|
}
|
|
|
|
VOID
|
|
NtfsCreateInternalStreamCommon (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN BOOLEAN UpdateScb,
|
|
IN BOOLEAN CompressedStream,
|
|
IN UNICODE_STRING const *StreamName
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsDeleteInternalAttributeStream (
|
|
IN PSCB Scb,
|
|
IN ULONG ForceClose,
|
|
IN ULONG CompressedStreamOnly
|
|
);
|
|
|
|
//
|
|
// The following routines provide direct access to data in an attribute.
|
|
//
|
|
|
|
VOID
|
|
NtfsMapStream (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN LONGLONG FileOffset,
|
|
IN ULONG Length,
|
|
OUT PVOID *Bcb,
|
|
OUT PVOID *Buffer
|
|
);
|
|
|
|
VOID
|
|
NtfsPinMappedData (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN LONGLONG FileOffset,
|
|
IN ULONG Length,
|
|
IN OUT PVOID *Bcb
|
|
);
|
|
|
|
VOID
|
|
NtfsPinStream (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN LONGLONG FileOffset,
|
|
IN ULONG Length,
|
|
OUT PVOID *Bcb,
|
|
OUT PVOID *Buffer
|
|
);
|
|
|
|
VOID
|
|
NtfsPreparePinWriteStream (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN LONGLONG FileOffset,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Zero,
|
|
OUT PVOID *Bcb,
|
|
OUT PVOID *Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCompleteMdl (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsZeroData (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN LONGLONG StartingZero,
|
|
IN LONGLONG ByteCount,
|
|
IN OUT PLONGLONG CommittedFileSize OPTIONAL
|
|
);
|
|
|
|
//
|
|
// The following is needed when biasing the SetFileSizes call for the Usn Journal.
|
|
//
|
|
// VOID
|
|
// NtfsSetCcFileSizes (
|
|
// IN PFILE_OBJECT FileObject,
|
|
// IN PSCB Scb,
|
|
// IN PCC_FILE_SIZES CcSizes
|
|
// );
|
|
//
|
|
|
|
#define NtfsSetCcFileSizes(FO,S,CC) { \
|
|
if (FlagOn( (S)->ScbPersist, SCB_PERSIST_USN_JOURNAL )) { \
|
|
CC_FILE_SIZES _CcSizes; \
|
|
RtlCopyMemory( &_CcSizes, (CC), sizeof( CC_FILE_SIZES )); \
|
|
_CcSizes.AllocationSize.QuadPart -= (S)->Vcb->UsnCacheBias; \
|
|
_CcSizes.FileSize.QuadPart -= (S)->Vcb->UsnCacheBias; \
|
|
CcSetFileSizes( (FO), &_CcSizes ); \
|
|
} else { \
|
|
CcSetFileSizes( (FO), (CC) ); \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// VOID
|
|
// NtfsFreeBcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN OUT PBCB *Bcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsUnpinBcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN OUT PBCB *Bcb,
|
|
// );
|
|
//
|
|
|
|
#define NtfsFreeBcb(IC,BC) { \
|
|
ASSERT_IRP_CONTEXT(IC); \
|
|
if (*(BC) != NULL) \
|
|
{ \
|
|
CcFreePinnedData(*(BC)); \
|
|
*(BC) = NULL; \
|
|
} \
|
|
}
|
|
|
|
|
|
#ifdef MAPCOUNT_DBG
|
|
#define NtfsUnpinBcb(IC,BC) { \
|
|
if (*(BC) != NULL) \
|
|
{ \
|
|
CcUnpinData(*(BC)); \
|
|
(IC)->MapCount--; \
|
|
*(BC) = NULL; \
|
|
} \
|
|
}
|
|
#else
|
|
#define NtfsUnpinBcb(IC,BC) { \
|
|
if (*(BC) != NULL) \
|
|
{ \
|
|
CcUnpinData(*(BC)); \
|
|
*(BC) = NULL; \
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
#ifdef MAPCOUNT_DBG
|
|
#define NtfsUnpinBcbForThread(IC,BC,T) { \
|
|
if (*(BC) != NULL) \
|
|
{ \
|
|
CcUnpinDataForThread(*(BC), (T)); \
|
|
(IC)->MapCount--; \
|
|
*(BC) = NULL; \
|
|
} \
|
|
}
|
|
#else
|
|
#define NtfsUnpinBcbForThread(IC,BC,T) { \
|
|
if (*(BC) != NULL) \
|
|
{ \
|
|
CcUnpinDataForThread(*(BC), (T)); \
|
|
*(BC) = NULL; \
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
INLINE
|
|
PBCB
|
|
NtfsRemapBcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PBCB Bcb
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( IrpContext );
|
|
#ifdef MAPCOUNT_DBG
|
|
IrpContext->MapCount++;
|
|
#endif
|
|
return CcRemapBcb( Bcb );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Ntfs structure check routines in CheckSup.c
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsCheckFileRecord (
|
|
IN PVCB Vcb,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN PFILE_REFERENCE FileReference OPTIONAL,
|
|
OUT PULONG CorruptionHint
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCheckAttributeRecord (
|
|
IN PVCB Vcb,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN PATTRIBUTE_RECORD_HEADER Attribute,
|
|
IN ULONG CheckHeaderOnly,
|
|
OUT PULONG CorruptionHint
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCheckIndexRoot (
|
|
IN PVCB Vcb,
|
|
IN PINDEX_ROOT IndexRoot,
|
|
IN ULONG AttributeSize
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCheckIndexBuffer (
|
|
IN PSCB Scb,
|
|
IN PINDEX_ALLOCATION_BUFFER IndexBuffer
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCheckIndexHeader (
|
|
IN PINDEX_HEADER IndexHeader,
|
|
IN ULONG BytesAvailable
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCheckLogRecord (
|
|
IN PNTFS_LOG_RECORD_HEADER LogRecord,
|
|
IN ULONG LogRecordLength,
|
|
IN TRANSACTION_ID TransactionId,
|
|
IN ULONG AttributeEntrySize
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCheckRestartTable (
|
|
IN PRESTART_TABLE RestartTable,
|
|
IN ULONG TableSize
|
|
);
|
|
|
|
|
|
//
|
|
// Collation routines, implemented in ColatSup.c
|
|
//
|
|
// These routines perform low-level collation operations, primarily
|
|
// for IndexSup. All of these routines are dispatched to via dispatch
|
|
// tables indexed by the collation rule. The dispatch tables are
|
|
// defined here, and the actual implementations are in colatsup.c
|
|
//
|
|
|
|
typedef
|
|
FSRTL_COMPARISON_RESULT
|
|
(*PCOMPARE_VALUES) (
|
|
IN PWCH UnicodeTable,
|
|
IN ULONG UnicodeTableSize,
|
|
IN PVOID Value,
|
|
IN PINDEX_ENTRY IndexEntry,
|
|
IN FSRTL_COMPARISON_RESULT WildCardIs,
|
|
IN BOOLEAN IgnoreCase
|
|
);
|
|
|
|
typedef
|
|
BOOLEAN
|
|
(*PIS_IN_EXPRESSION) (
|
|
IN PWCH UnicodeTable,
|
|
IN PVOID Value,
|
|
IN PINDEX_ENTRY IndexEntry,
|
|
IN BOOLEAN IgnoreCase
|
|
);
|
|
|
|
typedef
|
|
BOOLEAN
|
|
(*PARE_EQUAL) (
|
|
IN PWCH UnicodeTable,
|
|
IN PVOID Value,
|
|
IN PINDEX_ENTRY IndexEntry,
|
|
IN BOOLEAN IgnoreCase
|
|
);
|
|
|
|
typedef
|
|
BOOLEAN
|
|
(*PCONTAINS_WILDCARD) (
|
|
IN PVOID Value
|
|
);
|
|
|
|
typedef
|
|
VOID
|
|
(*PUPCASE_VALUE) (
|
|
IN PWCH UnicodeTable,
|
|
IN ULONG UnicodeTableSize,
|
|
IN OUT PVOID Value
|
|
);
|
|
|
|
extern PCOMPARE_VALUES NtfsCompareValues[COLLATION_NUMBER_RULES];
|
|
extern PIS_IN_EXPRESSION NtfsIsInExpression[COLLATION_NUMBER_RULES];
|
|
extern PARE_EQUAL NtfsIsEqual[COLLATION_NUMBER_RULES];
|
|
extern PCONTAINS_WILDCARD NtfsContainsWildcards[COLLATION_NUMBER_RULES];
|
|
extern PUPCASE_VALUE NtfsUpcaseValue[COLLATION_NUMBER_RULES];
|
|
|
|
BOOLEAN
|
|
NtfsFileNameIsInExpression (
|
|
IN PWCH UnicodeTable,
|
|
IN PFILE_NAME ExpressionName,
|
|
IN PFILE_NAME FileName,
|
|
IN BOOLEAN IgnoreCase
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFileNameIsEqual (
|
|
IN PWCH UnicodeTable,
|
|
IN PFILE_NAME ExpressionName,
|
|
IN PFILE_NAME FileName,
|
|
IN BOOLEAN IgnoreCase
|
|
);
|
|
|
|
|
|
//
|
|
// Compression on the wire routines in CowSup.c
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsCopyReadC (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN ULONG LockKey,
|
|
OUT PVOID Buffer,
|
|
OUT PMDL *MdlChain,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
OUT PCOMPRESSED_DATA_INFO CompressedDataInfo,
|
|
IN ULONG CompressedDataInfoLength,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCompressedCopyRead (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
OUT PVOID Buffer,
|
|
OUT PMDL *MdlChain,
|
|
OUT PCOMPRESSED_DATA_INFO CompressedDataInfo,
|
|
IN ULONG CompressedDataInfoLength,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PNTFS_ADVANCED_FCB_HEADER Header,
|
|
IN ULONG CompressionUnitSize,
|
|
IN ULONG ChunkSize
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsMdlReadCompleteCompressed (
|
|
IN struct _FILE_OBJECT *FileObject,
|
|
IN PMDL MdlChain,
|
|
IN struct _DEVICE_OBJECT *DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCopyWriteC (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN ULONG LockKey,
|
|
IN PVOID Buffer,
|
|
OUT PMDL *MdlChain,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PCOMPRESSED_DATA_INFO CompressedDataInfo,
|
|
IN ULONG CompressedDataInfoLength,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCompressedCopyWrite (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN PVOID Buffer,
|
|
OUT PMDL *MdlChain,
|
|
IN PCOMPRESSED_DATA_INFO CompressedDataInfo,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PNTFS_ADVANCED_FCB_HEADER Header,
|
|
IN ULONG CompressionUnitSize,
|
|
IN ULONG ChunkSize,
|
|
IN ULONG EngineMatches
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsMdlWriteCompleteCompressed (
|
|
IN struct _FILE_OBJECT *FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN PMDL MdlChain,
|
|
IN struct _DEVICE_OBJECT *DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsSynchronizeUncompressedIo (
|
|
IN PSCB Scb,
|
|
IN PLONGLONG FileOffset OPTIONAL,
|
|
IN ULONG Length,
|
|
IN ULONG WriteAccess,
|
|
IN OUT PCOMPRESSION_SYNC *CompressionSync
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsSynchronizeCompressedIo (
|
|
IN PSCB Scb,
|
|
IN PLONGLONG FileOffset,
|
|
IN ULONG Length,
|
|
IN ULONG WriteAccess,
|
|
IN OUT PCOMPRESSION_SYNC *CompressionSync
|
|
);
|
|
|
|
PCOMPRESSION_SYNC
|
|
NtfsAcquireCompressionSync (
|
|
IN LONGLONG FileOffset,
|
|
IN PSCB Scb,
|
|
IN ULONG WriteAccess
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseCompressionSync (
|
|
IN PCOMPRESSION_SYNC CompressionSync
|
|
);
|
|
|
|
INLINE
|
|
VOID
|
|
NtfsSetBothCacheSizes (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PCC_FILE_SIZES FileSizes,
|
|
IN PSCB Scb
|
|
)
|
|
|
|
{
|
|
if (Scb->NonpagedScb->SegmentObject.SharedCacheMap != NULL) {
|
|
NtfsSetCcFileSizes( FileObject, Scb, FileSizes );
|
|
}
|
|
|
|
#ifdef COMPRESS_ON_WIRE
|
|
if (Scb->Header.FileObjectC != NULL) {
|
|
CcSetFileSizes( Scb->Header.FileObjectC, FileSizes );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Device I/O routines, implemented in DevIoSup.c
|
|
//
|
|
// These routines perform the actual device read and writes. They only affect
|
|
// the on disk structure and do not alter any other data structures.
|
|
//
|
|
|
|
VOID
|
|
NtfsLockUserBuffer (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PIRP Irp,
|
|
IN LOCK_OPERATION Operation,
|
|
IN ULONG BufferLength
|
|
);
|
|
|
|
PVOID
|
|
NtfsMapUserBuffer (
|
|
IN OUT PIRP Irp,
|
|
IN MM_PAGE_PRIORITY Priority
|
|
);
|
|
|
|
PVOID
|
|
NtfsMapUserBufferNoRaise (
|
|
IN OUT PIRP Irp,
|
|
IN MM_PAGE_PRIORITY Priority
|
|
);
|
|
|
|
VOID
|
|
NtfsFillIrpBuffer (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN ULONG ByteCount,
|
|
IN ULONG Offset,
|
|
IN UCHAR Pattern
|
|
);
|
|
|
|
VOID
|
|
NtfsZeroEndOfSector (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PSCB Scb,
|
|
IN LONGLONG Offset,
|
|
IN BOOLEAN Cached
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsVolumeDasdIo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PSCB DasdScb,
|
|
IN PCCB Ccb,
|
|
IN VBO StartingVbo,
|
|
IN ULONG ByteCount
|
|
);
|
|
|
|
VOID
|
|
NtfsPagingFileIo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PSCB Scb,
|
|
IN VBO StartingVbo,
|
|
IN ULONG ByteCount
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsIsReadAheadThread (
|
|
);
|
|
|
|
//
|
|
// Values for StreamFlags passed to NtfsNonCachedIo, etc.
|
|
//
|
|
|
|
#define COMPRESSED_STREAM 0x00000001
|
|
#define ENCRYPTED_STREAM 0x00000002
|
|
|
|
NTSTATUS
|
|
NtfsNonCachedIo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PSCB Scb,
|
|
IN VBO StartingVbo,
|
|
IN ULONG ByteCount,
|
|
IN ULONG StreamFlags
|
|
);
|
|
|
|
VOID
|
|
NtfsNonCachedNonAlignedIo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PSCB Scb,
|
|
IN VBO StartingVbo,
|
|
IN ULONG ByteCount
|
|
);
|
|
|
|
#ifdef EFSDBG
|
|
NTSTATUS
|
|
NtfsDummyEfsRead (
|
|
IN OUT PUCHAR InOutBuffer,
|
|
IN PLARGE_INTEGER Offset,
|
|
IN ULONG BufferSize,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsDummyEfsWrite (
|
|
IN PUCHAR InBuffer,
|
|
OUT PUCHAR OutBuffer,
|
|
IN PLARGE_INTEGER Offset,
|
|
IN ULONG BufferSize,
|
|
IN PUCHAR Context
|
|
);
|
|
#endif
|
|
|
|
VOID
|
|
NtfsTransformUsaBlock (
|
|
IN PSCB Scb,
|
|
IN OUT PVOID SystemBuffer,
|
|
IN OUT PVOID Buffer,
|
|
IN ULONG Length
|
|
);
|
|
|
|
VOID
|
|
NtfsCreateMdlAndBuffer (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB ThisScb,
|
|
IN UCHAR NeedTwoBuffers,
|
|
IN OUT PULONG Length,
|
|
OUT PMDL *Mdl OPTIONAL,
|
|
OUT PVOID *Buffer
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteMdlAndBuffer (
|
|
IN PMDL Mdl OPTIONAL,
|
|
IN PVOID Buffer OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsWriteClusters (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PSCB Scb,
|
|
IN VBO StartingVbo,
|
|
IN PVOID Buffer,
|
|
IN ULONG ClusterCount
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsVerifyAndRevertUsaBlock (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PVOID SystemBuffer OPTIONAL,
|
|
IN ULONG Offset,
|
|
IN ULONG Length,
|
|
IN LONGLONG FileOffset
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsDefragFile (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsReadFromPlex(
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
|
|
//
|
|
// The following support routines are contained int Ea.c
|
|
//
|
|
|
|
PFILE_FULL_EA_INFORMATION
|
|
NtfsMapExistingEas (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
OUT PBCB *EaBcb,
|
|
OUT PULONG EaLength
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsBuildEaList (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN OUT PEA_LIST_HEADER EaListHeader,
|
|
IN PFILE_FULL_EA_INFORMATION UserEaList,
|
|
OUT PULONG_PTR ErrorOffset
|
|
);
|
|
|
|
VOID
|
|
NtfsReplaceFileEas (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PEA_LIST_HEADER EaList
|
|
);
|
|
|
|
|
|
//
|
|
// The following routines are used to manipulate the fscontext fields
|
|
// of the file object, implemented in FilObSup.c
|
|
//
|
|
|
|
typedef enum _TYPE_OF_OPEN {
|
|
|
|
UnopenedFileObject = 1,
|
|
UserFileOpen,
|
|
UserDirectoryOpen,
|
|
UserVolumeOpen,
|
|
StreamFileOpen,
|
|
UserViewIndexOpen
|
|
|
|
} TYPE_OF_OPEN;
|
|
|
|
VOID
|
|
NtfsSetFileObject (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN TYPE_OF_OPEN TypeOfOpen,
|
|
IN PSCB Scb,
|
|
IN PCCB Ccb OPTIONAL
|
|
);
|
|
|
|
//
|
|
// TYPE_OF_OPEN
|
|
// NtfsDecodeFileObject (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFILE_OBJECT FileObject,
|
|
// OUT PVCB *Vcb,
|
|
// OUT PFCB *Fcb,
|
|
// OUT PSCB *Scb,
|
|
// OUT PCCB *Ccb,
|
|
// IN BOOLEAN RaiseOnError
|
|
// );
|
|
//
|
|
|
|
#ifdef _DECODE_MACRO_
|
|
#define NtfsDecodeFileObject(IC,FO,V,F,S,C,R) ( \
|
|
( *(S) = (PSCB)(FO)->FsContext), \
|
|
((*(S) != NULL) \
|
|
? ((*(V) = (*(S))->Vcb), \
|
|
(*(C) = (PCCB)(FO)->FsContext2), \
|
|
(*(F) = (*(S))->Fcb), \
|
|
((R) \
|
|
&& !FlagOn((*(V))->VcbState, VCB_STATE_VOLUME_MOUNTED) \
|
|
&& ((*(C) == NULL) \
|
|
|| ((*(C))->TypeOfOpen != UserVolumeOpen) \
|
|
|| !FlagOn((*(V))->VcbState, VCB_STATE_LOCKED)) \
|
|
&& NtfsRaiseStatusFunction((IC), (STATUS_VOLUME_DISMOUNTED))), \
|
|
((*(C) == NULL) \
|
|
? StreamFileOpen \
|
|
: (*(C))->TypeOfOpen)) \
|
|
: (*(C) = NULL, \
|
|
UnopenedFileObject)) \
|
|
)
|
|
#else // _DECODE_MACRO_
|
|
|
|
INLINE TYPE_OF_OPEN
|
|
NtfsDecodeFileObject (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_OBJECT FileObject,
|
|
OUT PVCB *Vcb,
|
|
OUT PFCB *Fcb,
|
|
OUT PSCB *Scb,
|
|
OUT PCCB *Ccb,
|
|
IN BOOLEAN RaiseOnError
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine decodes a file object into a Vcb, Fcb, Scb, and Ccb.
|
|
|
|
Arguments:
|
|
|
|
IrpContext - The Irp context to use for raising on an error.
|
|
|
|
FileObject - The file object to decode.
|
|
|
|
Vcb - Where to store the Vcb.
|
|
|
|
Fcb - Where to store the Fcb.
|
|
|
|
Scb - Where to store the Scb.
|
|
|
|
Ccb - Where to store the Ccb.
|
|
|
|
RaiseOnError - If FALSE, we do not raise if we encounter an error.
|
|
Otherwise we do raise if we encounter an error.
|
|
|
|
Return Value:
|
|
|
|
Type of open
|
|
|
|
--*/
|
|
|
|
{
|
|
*Scb = (PSCB)FileObject->FsContext;
|
|
|
|
if (*Scb != NULL) {
|
|
|
|
*Vcb = (*Scb)->Vcb;
|
|
*Ccb = (PCCB)FileObject->FsContext2;
|
|
*Fcb = (*Scb)->Fcb;
|
|
|
|
//
|
|
// If the caller wants us to raise, let's see if there's anything
|
|
// we should raise.
|
|
//
|
|
|
|
if (RaiseOnError &&
|
|
!FlagOn((*Vcb)->VcbState, VCB_STATE_VOLUME_MOUNTED) &&
|
|
((*Ccb == NULL) ||
|
|
((*Ccb)->TypeOfOpen != UserVolumeOpen) ||
|
|
!FlagOn((*Vcb)->VcbState, VCB_STATE_LOCKED))) {
|
|
|
|
NtfsRaiseStatusFunction( IrpContext, STATUS_VOLUME_DISMOUNTED );
|
|
}
|
|
|
|
//
|
|
// Every open except a StreamFileOpen has a Ccb.
|
|
//
|
|
|
|
if (*Ccb == NULL) {
|
|
|
|
return StreamFileOpen;
|
|
|
|
} else {
|
|
|
|
return (*Ccb)->TypeOfOpen;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// No Scb, we assume the file wasn't open.
|
|
//
|
|
|
|
*Ccb = NULL;
|
|
return UnopenedFileObject;
|
|
}
|
|
}
|
|
#endif // _DECODE_MACRO_
|
|
|
|
//
|
|
// PSCB
|
|
// NtfsFastDecodeUserFileOpen (
|
|
// IN PFILE_OBJECT FileObject
|
|
// );
|
|
//
|
|
|
|
#define NtfsFastDecodeUserFileOpen(FO) ( \
|
|
(((FO)->FsContext2 != NULL) && (((PCCB)(FO)->FsContext2)->TypeOfOpen == UserFileOpen)) ? \
|
|
(PSCB)(FO)->FsContext : NULL \
|
|
)
|
|
|
|
VOID
|
|
NtfsUpdateScbFromFileObject (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PSCB Scb,
|
|
IN BOOLEAN CheckTimeStamps
|
|
);
|
|
|
|
//
|
|
// Ntfs-private FastIo routines.
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsCopyReadA (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Wait,
|
|
IN ULONG LockKey,
|
|
OUT PVOID Buffer,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCopyWriteA (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Wait,
|
|
IN ULONG LockKey,
|
|
IN PVOID Buffer,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsMdlReadA (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN ULONG LockKey,
|
|
OUT PMDL *MdlChain,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsPrepareMdlWriteA (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN ULONG LockKey,
|
|
OUT PMDL *MdlChain,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsWaitForIoAtEof (
|
|
IN PNTFS_ADVANCED_FCB_HEADER Header,
|
|
IN OUT PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length
|
|
);
|
|
|
|
VOID
|
|
NtfsFinishIoAtEof (
|
|
IN PNTFS_ADVANCED_FCB_HEADER Header
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// FsRtlLockFsRtlHeader (
|
|
// IN PNTFS_ADVANCED_FCB_HEADER FsRtlHeader
|
|
// );
|
|
//
|
|
// VOID
|
|
// FsRtlUnlockFsRtlHeader (
|
|
// IN PNTFS_ADVANCED_FCB_HEADER FsRtlHeader
|
|
// );
|
|
//
|
|
|
|
#define FsRtlLockFsRtlHeader(H) { \
|
|
ExAcquireFastMutex( (H)->FastMutex ); \
|
|
if (((H)->Flags & FSRTL_FLAG_EOF_ADVANCE_ACTIVE)) { \
|
|
NtfsWaitForIoAtEof( (H), &LiEof, 0 ); \
|
|
} \
|
|
(H)->Flags |= FSRTL_FLAG_EOF_ADVANCE_ACTIVE; \
|
|
ExReleaseFastMutex( (H)->FastMutex ); \
|
|
}
|
|
|
|
#define FsRtlUnlockFsRtlHeader(H) { \
|
|
ExAcquireFastMutex( (H)->FastMutex ); \
|
|
NtfsFinishIoAtEof( (H) ); \
|
|
ExReleaseFastMutex( (H)->FastMutex ); \
|
|
}
|
|
|
|
|
|
//
|
|
// Volume locking/unlocking routines, implemented in FsCtrl.c.
|
|
//
|
|
|
|
NTSTATUS
|
|
NtfsLockVolumeInternal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFILE_OBJECT FileObjectWithVcbLocked,
|
|
IN OUT PULONG Retrying
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsUnlockVolumeInternal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
|
|
//
|
|
// Indexing routine interfaces, implemented in IndexSup.c.
|
|
//
|
|
|
|
VOID
|
|
NtfsCreateIndex (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PFCB Fcb,
|
|
IN ATTRIBUTE_TYPE_CODE IndexedAttributeType,
|
|
IN COLLATION_RULE CollationRule,
|
|
IN ULONG BytesPerIndexBuffer,
|
|
IN UCHAR BlocksPerIndexBuffer,
|
|
IN PATTRIBUTE_ENUMERATION_CONTEXT Context OPTIONAL,
|
|
IN USHORT AttributeFlags,
|
|
IN BOOLEAN NewIndex,
|
|
IN BOOLEAN LogIt
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateIndexScbFromAttribute (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PATTRIBUTE_RECORD_HEADER IndexRootAttr,
|
|
IN ULONG MustBeFileName
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFindIndexEntry (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PVOID Value,
|
|
IN BOOLEAN IgnoreCase,
|
|
OUT PQUICK_INDEX QuickIndex OPTIONAL,
|
|
OUT PBCB *Bcb,
|
|
OUT PINDEX_ENTRY *IndexEntry,
|
|
OUT PINDEX_CONTEXT IndexContext OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateFileNameInIndex (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PFILE_NAME FileName,
|
|
IN PDUPLICATED_INFORMATION Info,
|
|
IN OUT PQUICK_INDEX QuickIndex OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsAddIndexEntry (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PVOID Value,
|
|
IN ULONG ValueLength,
|
|
IN PFILE_REFERENCE FileReference,
|
|
IN PINDEX_CONTEXT IndexContext OPTIONAL,
|
|
OUT PQUICK_INDEX QuickIndex OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteIndexEntry (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PVOID Value,
|
|
IN PFILE_REFERENCE FileReference
|
|
);
|
|
|
|
VOID
|
|
NtfsPushIndexRoot (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsRestartIndexEnumeration (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PCCB Ccb,
|
|
IN PSCB Scb,
|
|
IN PVOID Value,
|
|
IN BOOLEAN IgnoreCase,
|
|
IN BOOLEAN NextFlag,
|
|
OUT PINDEX_ENTRY *IndexEntry,
|
|
IN PFCB AcquiredFcb OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsContinueIndexEnumeration (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PCCB Ccb,
|
|
IN PSCB Scb,
|
|
IN BOOLEAN NextFlag,
|
|
OUT PINDEX_ENTRY *IndexEntry
|
|
);
|
|
|
|
PFILE_NAME
|
|
NtfsRetrieveOtherFileName (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PCCB Ccb,
|
|
IN PSCB Scb,
|
|
IN PINDEX_ENTRY IndexEntry,
|
|
IN OUT PINDEX_CONTEXT OtherContext,
|
|
IN PFCB AcquiredFcb OPTIONAL,
|
|
OUT PBOOLEAN SynchronizationError
|
|
);
|
|
|
|
VOID
|
|
NtfsCleanupAfterEnumeration (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PCCB Ccb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsIsIndexEmpty (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PATTRIBUTE_RECORD_HEADER Attribute
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteIndex (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PUNICODE_STRING AttributeName
|
|
);
|
|
|
|
VOID
|
|
NtfsInitializeIndexContext (
|
|
OUT PINDEX_CONTEXT IndexContext
|
|
);
|
|
|
|
VOID
|
|
NtfsCleanupIndexContext (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
OUT PINDEX_CONTEXT IndexContext
|
|
);
|
|
|
|
VOID
|
|
NtfsReinitializeIndexContext (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
OUT PINDEX_CONTEXT IndexContext
|
|
);
|
|
|
|
//
|
|
// PVOID
|
|
// NtfsFoundIndexEntry (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PINDEX_ENTRY IndexEntry
|
|
// );
|
|
//
|
|
|
|
#define NtfsFoundIndexEntry(IE) ((PVOID) \
|
|
((PUCHAR) (IE) + sizeof( INDEX_ENTRY )) \
|
|
)
|
|
|
|
//
|
|
// Restart routines for IndexSup
|
|
//
|
|
|
|
VOID
|
|
NtfsRestartInsertSimpleRoot (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PINDEX_ENTRY InsertIndexEntry,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN PATTRIBUTE_RECORD_HEADER Attribute,
|
|
IN PINDEX_ENTRY BeforeIndexEntry
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartInsertSimpleAllocation (
|
|
IN PINDEX_ENTRY InsertIndexEntry,
|
|
IN PINDEX_ALLOCATION_BUFFER IndexBuffer,
|
|
IN PINDEX_ENTRY BeforeIndexEntry
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartWriteEndOfIndex (
|
|
IN PINDEX_HEADER IndexHeader,
|
|
IN PINDEX_ENTRY OverwriteIndexEntry,
|
|
IN PINDEX_ENTRY FirstNewIndexEntry,
|
|
IN ULONG Length
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartSetIndexBlock(
|
|
IN PINDEX_ENTRY IndexEntry,
|
|
IN LONGLONG IndexBlock
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartUpdateFileName(
|
|
IN PINDEX_ENTRY IndexEntry,
|
|
IN PDUPLICATED_INFORMATION Info
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartDeleteSimpleRoot (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PINDEX_ENTRY IndexEntry,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN PATTRIBUTE_RECORD_HEADER Attribute
|
|
);
|
|
|
|
VOID
|
|
NtfsRestartDeleteSimpleAllocation (
|
|
IN PINDEX_ENTRY IndexEntry,
|
|
IN PINDEX_ALLOCATION_BUFFER IndexBuffer
|
|
);
|
|
|
|
VOID
|
|
NtOfsRestartUpdateDataInIndex(
|
|
IN PINDEX_ENTRY IndexEntry,
|
|
IN PVOID IndexData,
|
|
IN ULONG Length );
|
|
|
|
|
|
//
|
|
// Ntfs hashing routines, implemented in HashSup.c
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeHashTable (
|
|
IN OUT PNTFS_HASH_TABLE Table
|
|
);
|
|
|
|
VOID
|
|
NtfsUninitializeHashTable (
|
|
IN OUT PNTFS_HASH_TABLE Table
|
|
);
|
|
|
|
PLCB
|
|
NtfsFindPrefixHashEntry (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PNTFS_HASH_TABLE Table,
|
|
IN PSCB ParentScb,
|
|
IN OUT PULONG CreateFlags,
|
|
IN OUT PFCB *CurrentFcb,
|
|
OUT PULONG FileHashValue,
|
|
OUT PULONG FileNameLength,
|
|
OUT PULONG ParentHashValue,
|
|
OUT PULONG ParentNameLength,
|
|
IN OUT PUNICODE_STRING RemainingName
|
|
);
|
|
|
|
VOID
|
|
NtfsInsertHashEntry (
|
|
IN PNTFS_HASH_TABLE Table,
|
|
IN PLCB HashLcb,
|
|
IN ULONG NameLength,
|
|
IN ULONG HashValue
|
|
);
|
|
|
|
VOID
|
|
NtfsRemoveHashEntry (
|
|
IN PNTFS_HASH_TABLE Table,
|
|
IN PLCB HashLcb
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// NtfsRemoveHashEntriesForLcb (
|
|
// IN PLCB Lcb
|
|
// );
|
|
//
|
|
|
|
#define NtfsRemoveHashEntriesForLcb(L) { \
|
|
if (FlagOn( (L)->LcbState, LCB_STATE_VALID_HASH_VALUE )) { \
|
|
NtfsRemoveHashEntry( &(L)->Fcb->Vcb->HashTable, \
|
|
(L) ); \
|
|
} \
|
|
}
|
|
|
|
|
|
//
|
|
// Ntfs Logging Routine interfaces in LogSup.c
|
|
//
|
|
|
|
LSN
|
|
NtfsWriteLog (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PBCB Bcb OPTIONAL,
|
|
IN NTFS_LOG_OPERATION RedoOperation,
|
|
IN PVOID RedoBuffer OPTIONAL,
|
|
IN ULONG RedoLength,
|
|
IN NTFS_LOG_OPERATION UndoOperation,
|
|
IN PVOID UndoBuffer OPTIONAL,
|
|
IN ULONG UndoLength,
|
|
IN LONGLONG StreamOffset,
|
|
IN ULONG RecordOffset,
|
|
IN ULONG AttributeOffset,
|
|
IN ULONG StructureSize
|
|
);
|
|
|
|
VOID
|
|
NtfsCheckpointVolume (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN OwnsCheckpoint,
|
|
IN BOOLEAN CleanVolume,
|
|
IN BOOLEAN FlushVolume,
|
|
IN ULONG LfsFlags,
|
|
IN LSN LastKnownLsn
|
|
);
|
|
|
|
VOID
|
|
NtfsCheckpointForLogFileFull (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCheckpointForVolumeSnapshot (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
VOID
|
|
NtfsCleanCheckpoint (
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsCommitCurrentTransaction (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
VOID
|
|
NtfsCheckpointCurrentTransaction (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
VOID
|
|
NtfsInitializeLogging (
|
|
);
|
|
|
|
VOID
|
|
NtfsStartLogFile (
|
|
IN PSCB LogFileScb,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsStopLogFile (
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsInitializeRestartTable (
|
|
IN ULONG EntrySize,
|
|
IN ULONG NumberEntries,
|
|
OUT PRESTART_POINTERS TablePointer
|
|
);
|
|
|
|
VOID
|
|
InitializeNewTable (
|
|
IN ULONG EntrySize,
|
|
IN ULONG NumberEntries,
|
|
OUT PRESTART_POINTERS TablePointer
|
|
);
|
|
|
|
VOID
|
|
NtfsFreeRestartTable (
|
|
IN PRESTART_POINTERS TablePointer
|
|
);
|
|
|
|
VOID
|
|
NtfsExtendRestartTable (
|
|
IN PRESTART_POINTERS TablePointer,
|
|
IN ULONG NumberNewEntries,
|
|
IN ULONG FreeGoal
|
|
);
|
|
|
|
ULONG
|
|
NtfsAllocateRestartTableIndex (
|
|
IN PRESTART_POINTERS TablePointer,
|
|
IN ULONG Exclusive
|
|
);
|
|
|
|
PVOID
|
|
NtfsAllocateRestartTableFromIndex (
|
|
IN PRESTART_POINTERS TablePointer,
|
|
IN ULONG Index
|
|
);
|
|
|
|
VOID
|
|
NtfsFreeRestartTableIndex (
|
|
IN PRESTART_POINTERS TablePointer,
|
|
IN ULONG Index
|
|
);
|
|
|
|
PVOID
|
|
NtfsGetFirstRestartTable (
|
|
IN PRESTART_POINTERS TablePointer
|
|
);
|
|
|
|
PVOID
|
|
NtfsGetNextRestartTable (
|
|
IN PRESTART_POINTERS TablePointer,
|
|
IN PVOID Current
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateOatVersion (
|
|
IN PVCB Vcb,
|
|
IN ULONG NewRestartVersion
|
|
);
|
|
|
|
VOID
|
|
NtfsFreeRecentlyDeallocated (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PLSN BaseLsn,
|
|
IN ULONG CleanVolume
|
|
);
|
|
|
|
//
|
|
//
|
|
// VOID
|
|
// NtfsFreeOpenAttributeData (
|
|
// IN POPEN_ATTRIBUTE_DATA Entry
|
|
// );
|
|
//
|
|
|
|
#define NtfsFreeOpenAttributeData(E) { \
|
|
RemoveEntryList( &(E)->Links ); \
|
|
NtfsFreePool( E ); \
|
|
}
|
|
|
|
VOID
|
|
NtfsFreeAttributeEntry (
|
|
IN PVCB Vcb,
|
|
IN POPEN_ATTRIBUTE_ENTRY AttributeEntry
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// NtfsNormalizeAndCleanupTransaction (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN NTSTATUS *Status,
|
|
// IN BOOLEAN AlwaysRaise,
|
|
// IN NTSTATUS NormalizeStatus
|
|
// );
|
|
//
|
|
|
|
#define NtfsNormalizeAndCleanupTransaction(IC,PSTAT,RAISE,NORM_STAT) { \
|
|
if (!NT_SUCCESS( (IC)->TopLevelIrpContext->ExceptionStatus )) { \
|
|
NtfsRaiseStatus( (IC), (IC)->TopLevelIrpContext->ExceptionStatus, NULL, NULL ); \
|
|
} else if (!NT_SUCCESS( *(PSTAT) )) { \
|
|
*(PSTAT) = FsRtlNormalizeNtstatus( *(PSTAT), (NORM_STAT) ); \
|
|
if ((RAISE) || ((IC)->TopLevelIrpContext->TransactionId != 0)) { \
|
|
NtfsRaiseStatus( (IC), *(PSTAT), NULL, NULL ); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// VOID
|
|
// NtfsCleanupTransaction (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN NTSTATUS Status,
|
|
// IN BOOLEAN AlwaysRaise
|
|
// );
|
|
//
|
|
|
|
|
|
#define NtfsCleanupTransaction(IC,STAT,RAISE) { \
|
|
if (!NT_SUCCESS( (IC)->TopLevelIrpContext->ExceptionStatus )) { \
|
|
NtfsRaiseStatus( (IC), (IC)->TopLevelIrpContext->ExceptionStatus, NULL, NULL ); \
|
|
} else if (!NT_SUCCESS( STAT ) && \
|
|
((RAISE) || ((IC)->TopLevelIrpContext->TransactionId != 0))) { \
|
|
NtfsRaiseStatus( (IC), (STAT), NULL, NULL ); \
|
|
} else if (((IC)->Usn.NewReasons != 0) || ((IC)->Usn.RemovedSourceInfo != 0)) { \
|
|
NtfsWriteUsnJournalChanges( (IC) ); \
|
|
NtfsCommitCurrentTransaction( (IC) ); \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// VOID
|
|
// NtfsCleanupTransactionAndCommit (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN NTSTATUS Status,
|
|
// IN BOOLEAN AlwaysRaise
|
|
// );
|
|
//
|
|
|
|
#define NtfsCleanupTransactionAndCommit(IC,STAT,RAISE) { \
|
|
if (!NT_SUCCESS( (IC)->TopLevelIrpContext->ExceptionStatus )) { \
|
|
NtfsRaiseStatus( (IC), (IC)->TopLevelIrpContext->ExceptionStatus, NULL, NULL ); \
|
|
} else if (!NT_SUCCESS( STAT ) && \
|
|
((RAISE) || ((IC)->TopLevelIrpContext->TransactionId != 0))) { \
|
|
NtfsRaiseStatus( (IC), (STAT), NULL, NULL ); \
|
|
} else if (((IC)->Usn.NewReasons != 0) || ((IC)->Usn.RemovedSourceInfo != 0)) { \
|
|
NtfsWriteUsnJournalChanges( (IC) ); \
|
|
NtfsCheckpointCurrentTransaction( (IC) ); \
|
|
} else { \
|
|
NtfsCheckpointCurrentTransaction( (IC) ); \
|
|
} \
|
|
}
|
|
|
|
VOID
|
|
NtfsCleanupFailedTransaction (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
|
|
//
|
|
// NTFS MCB support routine, implemented in McbSup.c
|
|
//
|
|
|
|
//
|
|
// An Ntfs Mcb is a superset of the regular mcb package. In
|
|
// addition to the regular Mcb functions it will unload mapping
|
|
// information to keep it overall memory usage down
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeNtfsMcb (
|
|
IN PNTFS_MCB Mcb,
|
|
IN PNTFS_ADVANCED_FCB_HEADER FcbHeader,
|
|
IN PNTFS_MCB_INITIAL_STRUCTS McbStructs,
|
|
IN POOL_TYPE PoolType
|
|
);
|
|
|
|
VOID
|
|
NtfsUninitializeNtfsMcb (
|
|
IN PNTFS_MCB Mcb
|
|
);
|
|
|
|
VOID
|
|
NtfsRemoveNtfsMcbEntry (
|
|
IN PNTFS_MCB Mcb,
|
|
IN LONGLONG Vcn,
|
|
IN LONGLONG Count
|
|
);
|
|
|
|
VOID
|
|
NtfsUnloadNtfsMcbRange (
|
|
IN PNTFS_MCB Mcb,
|
|
IN LONGLONG StartingVcn,
|
|
IN LONGLONG EndingVcn,
|
|
IN BOOLEAN TruncateOnly,
|
|
IN BOOLEAN AlreadySynchronized
|
|
);
|
|
|
|
ULONG
|
|
NtfsNumberOfRangesInNtfsMcb (
|
|
IN PNTFS_MCB Mcb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsNumberOfRunsInRange(
|
|
IN PNTFS_MCB Mcb,
|
|
IN PVOID RangePtr,
|
|
OUT PULONG NumberOfRuns
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsLookupLastNtfsMcbEntry (
|
|
IN PNTFS_MCB Mcb,
|
|
OUT PLONGLONG Vcn,
|
|
OUT PLONGLONG Lcn
|
|
);
|
|
|
|
ULONG
|
|
NtfsMcbLookupArrayIndex (
|
|
IN PNTFS_MCB Mcb,
|
|
IN VCN Vcn
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsSplitNtfsMcb (
|
|
IN PNTFS_MCB Mcb,
|
|
IN LONGLONG Vcn,
|
|
IN LONGLONG Amount
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsAddNtfsMcbEntry (
|
|
IN PNTFS_MCB Mcb,
|
|
IN LONGLONG Vcn,
|
|
IN LONGLONG Lcn,
|
|
IN LONGLONG RunCount,
|
|
IN BOOLEAN AlreadySynchronized
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsLookupNtfsMcbEntry (
|
|
IN PNTFS_MCB Mcb,
|
|
IN LONGLONG Vcn,
|
|
OUT PLONGLONG Lcn OPTIONAL,
|
|
OUT PLONGLONG CountFromLcn OPTIONAL,
|
|
OUT PLONGLONG StartingLcn OPTIONAL,
|
|
OUT PLONGLONG CountFromStartingLcn OPTIONAL,
|
|
OUT PVOID *RangePtr OPTIONAL,
|
|
OUT PULONG RunIndex OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsGetNextNtfsMcbEntry (
|
|
IN PNTFS_MCB Mcb,
|
|
IN PVOID *RangePtr,
|
|
IN ULONG RunIndex,
|
|
OUT PLONGLONG Vcn,
|
|
OUT PLONGLONG Lcn,
|
|
OUT PLONGLONG Count
|
|
);
|
|
|
|
//
|
|
// BOOLEAN
|
|
// NtfsGetSequentialMcbEntry (
|
|
// IN PNTFS_MCB Mcb,
|
|
// IN PVOID *RangePtr,
|
|
// IN ULONG RunIndex,
|
|
// OUT PLONGLONG Vcn,
|
|
// OUT PLONGLONG Lcn,
|
|
// OUT PLONGLONG Count
|
|
// );
|
|
//
|
|
|
|
#define NtfsGetSequentialMcbEntry(MC,RGI,RNI,V,L,C) ( \
|
|
NtfsGetNextNtfsMcbEntry(MC,RGI,RNI,V,L,C) || \
|
|
(RNI = 0) || \
|
|
NtfsGetNextNtfsMcbEntry(MC,RGI,MAXULONG,V,L,C) || \
|
|
((RNI = MAXULONG) == 0) \
|
|
)
|
|
|
|
|
|
VOID
|
|
NtfsDefineNtfsMcbRange (
|
|
IN PNTFS_MCB Mcb,
|
|
IN LONGLONG StartingVcn,
|
|
IN LONGLONG EndingVcn,
|
|
IN BOOLEAN AlreadySynchronized
|
|
);
|
|
|
|
VOID
|
|
NtfsSwapMcbs (
|
|
IN PNTFS_MCB McbTarget,
|
|
IN PNTFS_MCB McbSource
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// NtfsAcquireNtfsMcbMutex (
|
|
// IN PNTFS_MCB Mcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReleaseNtfsMcbMutex (
|
|
// IN PNTFS_MCB Mcb
|
|
// );
|
|
//
|
|
|
|
#define NtfsAcquireNtfsMcbMutex(M) { \
|
|
ExAcquireFastMutex((M)->FastMutex); \
|
|
}
|
|
|
|
#define NtfsReleaseNtfsMcbMutex(M) { \
|
|
ExReleaseFastMutex((M)->FastMutex); \
|
|
}
|
|
|
|
|
|
//
|
|
// MFT access routines, implemented in MftSup.c
|
|
//
|
|
|
|
//
|
|
// Mft map cache routines. We maintain a cache of active maps in the
|
|
// IRP_CONTEXT and consult this if we need to map a file record.
|
|
//
|
|
|
|
INLINE
|
|
PIRP_FILE_RECORD_CACHE_ENTRY
|
|
NtfsFindFileRecordCacheEntry (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN ULONG UnsafeSegmentNumber
|
|
)
|
|
{
|
|
#if (IRP_FILE_RECORD_MAP_CACHE_SIZE <= 4)
|
|
#define PROBECACHE(ic,sn,i) \
|
|
ASSERT((ic)->FileRecordCache[(i)].FileRecordBcb != NULL); \
|
|
if ((ic)->FileRecordCache[(i)].UnsafeSegmentNumber == (sn)) \
|
|
{ \
|
|
return IrpContext->FileRecordCache + (i); \
|
|
}
|
|
|
|
// DebugTrace( 0, 0, ("Context %08x finding %x\n", IrpContext, UnsafeSegmentNumber ));
|
|
ASSERT(IrpContext->CacheCount <= 4);
|
|
switch (IrpContext->CacheCount) {
|
|
case 4:
|
|
PROBECACHE( IrpContext, UnsafeSegmentNumber, 3 );
|
|
// Fallthru
|
|
|
|
case 3:
|
|
PROBECACHE( IrpContext, UnsafeSegmentNumber, 2 );
|
|
// Fallthru
|
|
|
|
case 2:
|
|
PROBECACHE( IrpContext, UnsafeSegmentNumber, 1 );
|
|
// Fallthru
|
|
|
|
case 1:
|
|
PROBECACHE( IrpContext, UnsafeSegmentNumber, 0 );
|
|
// Fallthru
|
|
|
|
case 0:
|
|
|
|
//
|
|
// redundant default case (and matching assert above) added to quiet
|
|
// warning 4715:
|
|
//
|
|
// "not all control paths return a value."
|
|
//
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
#else
|
|
PIRP_FILE_RECORD_CACHE_ENTRY Entry;
|
|
|
|
for (Entry = IrpContext->FileRecordCache;
|
|
Entry < IrpContext->FileRecordCache + IrpContext->CacheCount;
|
|
Entry++) {
|
|
ASSERT( Entry->FileRecordBcb != NULL);
|
|
if (Entry->UnsafeSegmentNumber == UnsafeSegmentNumber) {
|
|
return Entry;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
INLINE
|
|
VOID
|
|
NtfsRemoveFromFileRecordCache (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN ULONG UnsafeSegmentNumber
|
|
)
|
|
{
|
|
PIRP_FILE_RECORD_CACHE_ENTRY Entry =
|
|
NtfsFindFileRecordCacheEntry( IrpContext, UnsafeSegmentNumber );
|
|
|
|
// DebugTrace( 0, 0, ("Context %08x removing %x\n", IrpContext, Entry ));
|
|
if (Entry != NULL) {
|
|
|
|
ASSERT( Entry->FileRecordBcb != NULL );
|
|
|
|
//
|
|
// We delete the entry at position [i] by dereferencing the Bcb and
|
|
// copying the entire structure from [IrpContext->CacheCount]
|
|
//
|
|
|
|
NtfsUnpinBcb( IrpContext, &Entry->FileRecordBcb );
|
|
|
|
//
|
|
// Decrement the active count. If there are no more cache entries,
|
|
// then we're done.
|
|
//
|
|
|
|
IrpContext->CacheCount--;
|
|
if (IrpContext->FileRecordCache + IrpContext->CacheCount != Entry) {
|
|
*Entry = IrpContext->FileRecordCache[IrpContext->CacheCount];
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef KDEXT
|
|
|
|
INLINE
|
|
VOID
|
|
NtfsAddToFileRecordCache (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN ULONG UnsafeSegmentNumber,
|
|
IN PBCB FileRecordBcb,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord
|
|
)
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
if (IrpContext->CacheCount < IRP_FILE_RECORD_MAP_CACHE_SIZE) {
|
|
// DebugTrace( 0, 0, ("Context %08x adding %x at %x\n", IrpContext, UnsafeSegmentNumber,
|
|
// IrpContext->FileRecordCache + IrpContext->CacheCount ));
|
|
IrpContext->FileRecordCache[IrpContext->CacheCount].UnsafeSegmentNumber =
|
|
UnsafeSegmentNumber;
|
|
IrpContext->FileRecordCache[IrpContext->CacheCount].FileRecordBcb =
|
|
NtfsRemapBcb( IrpContext, FileRecordBcb );
|
|
IrpContext->FileRecordCache[IrpContext->CacheCount].FileRecord = FileRecord;
|
|
IrpContext->CacheCount++;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
INLINE
|
|
VOID
|
|
NtfsPurgeFileRecordCache (
|
|
IN PIRP_CONTEXT IrpContext
|
|
)
|
|
{
|
|
while (IrpContext->CacheCount) {
|
|
|
|
IrpContext->CacheCount --;
|
|
// DebugTrace( 0, 0, ("Context %08x purging %x\n", IrpContext, IrpContext->FileRecordCache + IrpContext->CacheCount ));
|
|
NtfsUnpinBcb( IrpContext, &IrpContext->FileRecordCache[IrpContext->CacheCount].FileRecordBcb );
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
extern ULONG FileRecordCacheHitArray[IRP_FILE_RECORD_MAP_CACHE_SIZE];
|
|
#endif // DBG
|
|
|
|
INLINE
|
|
BOOLEAN
|
|
NtfsFindCachedFileRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN ULONG UnsafeSegmentNumber,
|
|
OUT PBCB *Bcb,
|
|
OUT PFILE_RECORD_SEGMENT_HEADER *FileRecord
|
|
)
|
|
{
|
|
PIRP_FILE_RECORD_CACHE_ENTRY Entry =
|
|
NtfsFindFileRecordCacheEntry( IrpContext, UnsafeSegmentNumber );
|
|
|
|
// DebugTrace( 0, 0, ("Context %x finding %x = %x\n", IrpContext, UnsafeSegmentNumber, Entry ));
|
|
|
|
if (Entry == NULL) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
*Bcb = NtfsRemapBcb( IrpContext, Entry->FileRecordBcb );
|
|
*FileRecord = Entry->FileRecord;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// This routine may only be used to read the Base file record segment, and
|
|
// it checks that this is true.
|
|
//
|
|
|
|
VOID
|
|
NtfsReadFileRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFILE_REFERENCE FileReference,
|
|
OUT PBCB *Bcb,
|
|
OUT PFILE_RECORD_SEGMENT_HEADER *BaseFileRecord,
|
|
OUT PATTRIBUTE_RECORD_HEADER *FirstAttribute,
|
|
OUT PLONGLONG MftFileOffset OPTIONAL
|
|
);
|
|
|
|
//
|
|
// These routines can read/pin any record in the MFT.
|
|
//
|
|
|
|
VOID
|
|
NtfsReadMftRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PMFT_SEGMENT_REFERENCE SegmentReference,
|
|
IN BOOLEAN CheckRecord,
|
|
OUT PBCB *Bcb,
|
|
OUT PFILE_RECORD_SEGMENT_HEADER *FileRecord,
|
|
OUT PLONGLONG MftFileOffset OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsPinMftRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PMFT_SEGMENT_REFERENCE SegmentReference,
|
|
IN BOOLEAN PreparingToWrite,
|
|
OUT PBCB *Bcb,
|
|
OUT PFILE_RECORD_SEGMENT_HEADER *FileRecord,
|
|
OUT PLONGLONG MftFileOffset OPTIONAL
|
|
);
|
|
|
|
//
|
|
// The following routines are used to setup, allocate, and deallocate
|
|
// file records in the Mft.
|
|
//
|
|
|
|
MFT_SEGMENT_REFERENCE
|
|
NtfsAllocateMftRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN MftData
|
|
);
|
|
|
|
VOID
|
|
NtfsInitializeMftRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN OUT PMFT_SEGMENT_REFERENCE MftSegment,
|
|
IN OUT PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN PBCB Bcb,
|
|
IN BOOLEAN Directory
|
|
);
|
|
|
|
VOID
|
|
NtfsDeallocateMftRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN ULONG FileNumber
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsIsMftIndexInHole (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN ULONG Index,
|
|
OUT PULONG HoleLength OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsFillMftHole (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN ULONG Index
|
|
);
|
|
|
|
VOID
|
|
NtfsLogMftFileRecord (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN LONGLONG MftOffset,
|
|
IN PBCB FileRecordBcb,
|
|
IN BOOLEAN RedoOperation
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsDefragMft (
|
|
IN PDEFRAG_MFT DefragMft
|
|
);
|
|
|
|
VOID
|
|
NtfsCheckForDefrag (
|
|
IN OUT PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsInitializeMftHoleRecords (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN ULONG FirstIndex,
|
|
IN ULONG RecordCount
|
|
);
|
|
|
|
|
|
//
|
|
// Name support routines, implemented in NameSup.c
|
|
//
|
|
|
|
typedef enum _PARSE_TERMINATION_REASON {
|
|
|
|
EndOfPathReached,
|
|
NonSimpleName,
|
|
IllegalCharacterInName,
|
|
MalFormedName,
|
|
AttributeOnly,
|
|
VersionNumberPresent
|
|
|
|
} PARSE_TERMINATION_REASON;
|
|
|
|
|
|
INLINE
|
|
NTSTATUS
|
|
NtfsDissectName(
|
|
IN UNICODE_STRING Path,
|
|
OUT PUNICODE_STRING FirstName,
|
|
OUT PUNICODE_STRING RemainingName
|
|
)
|
|
{
|
|
FsRtlDissectName( Path, FirstName, RemainingName );
|
|
|
|
//
|
|
// Remaining name cannot start with a slash
|
|
//
|
|
|
|
if ((RemainingName->Length != 0) && (RemainingName->Buffer[0] == L'\\')) {
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
} else {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
NtfsParseName (
|
|
IN const UNICODE_STRING Name,
|
|
IN BOOLEAN WildCardsPermissible,
|
|
OUT PBOOLEAN FoundIllegalCharacter,
|
|
OUT PNTFS_NAME_DESCRIPTOR ParsedName
|
|
);
|
|
|
|
PARSE_TERMINATION_REASON
|
|
NtfsParsePath (
|
|
IN UNICODE_STRING Path,
|
|
IN BOOLEAN WildCardsPermissible,
|
|
OUT PUNICODE_STRING FirstPart,
|
|
OUT PNTFS_NAME_DESCRIPTOR Name,
|
|
OUT PUNICODE_STRING RemainingPart
|
|
);
|
|
|
|
VOID
|
|
NtfsPreprocessName (
|
|
IN UNICODE_STRING InputString,
|
|
OUT PUNICODE_STRING FirstPart,
|
|
OUT PUNICODE_STRING AttributeCode,
|
|
OUT PUNICODE_STRING AttributeName,
|
|
OUT PBOOLEAN TrailingBackslash
|
|
);
|
|
|
|
VOID
|
|
NtfsUpcaseName (
|
|
IN PWCH UpcaseTable,
|
|
IN ULONG UpcaseTableSize,
|
|
IN OUT PUNICODE_STRING InputString
|
|
);
|
|
|
|
FSRTL_COMPARISON_RESULT
|
|
NtfsCollateNames (
|
|
IN PCWCH UpcaseTable,
|
|
IN ULONG UpcaseTableSize,
|
|
IN PCUNICODE_STRING Expression,
|
|
IN PCUNICODE_STRING Name,
|
|
IN FSRTL_COMPARISON_RESULT WildIs,
|
|
IN BOOLEAN IgnoreCase
|
|
);
|
|
|
|
#define NtfsIsNameInExpression(UC,EX,NM,IC) \
|
|
FsRtlIsNameInExpression( (EX), (NM), (IC), (UC) )
|
|
|
|
BOOLEAN
|
|
NtfsIsFileNameValid (
|
|
IN PUNICODE_STRING FileName,
|
|
IN BOOLEAN WildCardsPermissible
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsIsFatNameValid (
|
|
IN PUNICODE_STRING FileName,
|
|
IN BOOLEAN WildCardsPermissible
|
|
);
|
|
|
|
//
|
|
// Ntfs works very hard to make sure that all names are kept in upper case
|
|
// so that most comparisons are done case SENSITIVE. Name testing for
|
|
// case SENSITIVE can be very quick since RtlEqualMemory is an inline operation
|
|
// on several processors.
|
|
//
|
|
// NtfsAreNamesEqual is used when the caller does not know for sure whether
|
|
// or not case is important. In the case where IgnoreCase is a known value,
|
|
// the compiler can easily optimize the relevant clause.
|
|
//
|
|
|
|
#define NtfsAreNamesEqual(UpcaseTable,Name1,Name2,IgnoreCase) \
|
|
((IgnoreCase) ? FsRtlAreNamesEqual( (Name1), (Name2), (IgnoreCase), (UpcaseTable) ) \
|
|
: ((Name1)->Length == (Name2)->Length && \
|
|
RtlEqualMemory( (Name1)->Buffer, (Name2)->Buffer, (Name1)->Length )))
|
|
|
|
|
|
//
|
|
// Object id support routines, implemented in ObjIdSup.c
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeObjectIdIndex (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsSetObjectId (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsSetObjectIdExtendedInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsSetObjectIdInternal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PVCB Vcb,
|
|
IN PFILE_OBJECTID_BUFFER ObjectIdBuffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCreateOrGetObjectId (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsGetObjectId (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsGetObjectIdInternal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN BOOLEAN GetExtendedInfo,
|
|
OUT FILE_OBJECTID_BUFFER *OutputBuffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsGetObjectIdExtendedInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN UCHAR *ObjectId,
|
|
IN OUT UCHAR *ExtendedInfo
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsDeleteObjectId (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsDeleteObjectIdInternal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN DeleteFileAttribute
|
|
);
|
|
|
|
VOID
|
|
NtfsRepairObjectId (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVOID Context
|
|
);
|
|
|
|
|
|
//
|
|
// Mount point support routines, implemented in MountSup.c
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeReparsePointIndex (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsValidateReparsePointBuffer (
|
|
IN ULONG BufferLength,
|
|
IN PREPARSE_DATA_BUFFER ReparseBuffer
|
|
);
|
|
|
|
|
|
//
|
|
// Largest matching prefix searching routines, implemented in PrefxSup.c
|
|
//
|
|
|
|
VOID
|
|
NtfsInsertPrefix (
|
|
IN PLCB Lcb,
|
|
IN ULONG CreateFlags
|
|
);
|
|
|
|
VOID
|
|
NtfsRemovePrefix (
|
|
IN PLCB Lcb
|
|
);
|
|
|
|
PLCB
|
|
NtfsFindPrefix (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB StartingScb,
|
|
OUT PFCB *CurrentFcb,
|
|
OUT PLCB *LcbForTeardown,
|
|
IN OUT UNICODE_STRING FullFileName,
|
|
IN OUT PULONG CreateFlags,
|
|
OUT PUNICODE_STRING RemainingName
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsInsertNameLink (
|
|
IN PRTL_SPLAY_LINKS *RootNode,
|
|
IN PNAME_LINK NameLink
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// NtfsRemoveNameLink (
|
|
// IN PRTL_SPLAY_LINKS *RootNode,
|
|
// IN PNAME_LINK NameLink
|
|
// );
|
|
//
|
|
|
|
#define NtfsRemoveNameLink(RN,NL) { \
|
|
*(RN) = RtlDelete( &(NL)->Links ); \
|
|
}
|
|
|
|
PNAME_LINK
|
|
NtfsFindNameLink (
|
|
IN PRTL_SPLAY_LINKS *RootNode,
|
|
IN PUNICODE_STRING Name
|
|
);
|
|
|
|
//
|
|
// The following macro is useful for traversing the queue of Prefixes
|
|
// attached to a given Lcb
|
|
//
|
|
// PPREFIX_ENTRY
|
|
// NtfsGetNextPrefix (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PLCB Lcb,
|
|
// IN PPREFIX_ENTRY PreviousPrefixEntry
|
|
// );
|
|
//
|
|
|
|
#define NtfsGetNextPrefix(IC,LC,PPE) ((PPREFIX_ENTRY) \
|
|
((PPE) == NULL ? \
|
|
(IsListEmpty(&(LC)->PrefixQueue) ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD((LC)->PrefixQueue.Flink, PREFIX_ENTRY, LcbLinks.Flink) \
|
|
) \
|
|
: \
|
|
((PVOID)((PPREFIX_ENTRY)(PPE))->LcbLinks.Flink == &(LC)->PrefixQueue.Flink ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD(((PPREFIX_ENTRY)(PPE))->LcbLinks.Flink, PREFIX_ENTRY, LcbLinks.Flink) \
|
|
) \
|
|
) \
|
|
)
|
|
|
|
|
|
//
|
|
// Resources support routines/macros, implemented in ResrcSup.c
|
|
//
|
|
|
|
//
|
|
// Flags used in the acquire routines
|
|
//
|
|
|
|
#define ACQUIRE_NO_DELETE_CHECK (0x00000001)
|
|
#define ACQUIRE_DONT_WAIT (0x00000002)
|
|
#define ACQUIRE_HOLD_BITMAP (0x00000004)
|
|
#define ACQUIRE_WAIT (0x00000008)
|
|
|
|
//
|
|
// VOID
|
|
// NtfsAcquireExclusiveGlobal (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN BOOLEAN Wait
|
|
// );
|
|
//
|
|
// BOOLEAN
|
|
// NtfsAcquireSharedGlobal (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN BOOLEAN Wait
|
|
// );
|
|
//
|
|
|
|
|
|
#define NtfsAcquireSharedGlobal( I, W ) ExAcquireResourceSharedLite( &NtfsData.Resource, (W) )
|
|
|
|
#define NtfsAcquireExclusiveGlobal( I, W ) ExAcquireResourceExclusiveLite( &NtfsData.Resource, (W) )
|
|
|
|
VOID
|
|
NtfsAcquireCheckpointSynchronization (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseCheckpointSynchronization (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// NtfsLockNtfsData (
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsUnlockNtfsData (
|
|
// );
|
|
//
|
|
|
|
#define NtfsLockNtfsData() { \
|
|
ExAcquireFastMutex( &NtfsData.NtfsDataLock ); \
|
|
}
|
|
|
|
#define NtfsUnlockNtfsData() { \
|
|
ExReleaseFastMutex( &NtfsData.NtfsDataLock ); \
|
|
}
|
|
|
|
VOID
|
|
NtfsAcquireAllFiles (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN ULONG Exclusive,
|
|
IN ULONG AcquirePagingIo,
|
|
IN ULONG AcquireAndDrop
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseAllFiles (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN ReleasePagingIo
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsAcquireExclusiveVcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN RaiseOnCantWait
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsAcquireSharedVcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN RaiseOnCantWait
|
|
);
|
|
|
|
#define NtfsAcquireExclusivePagingIo(IC,FCB) { \
|
|
ASSERT((IC)->CleanupStructure == NULL); \
|
|
NtfsAcquirePagingResourceExclusive( IC, FCB, TRUE ); \
|
|
(IC)->CleanupStructure = (FCB); \
|
|
}
|
|
|
|
#define NtfsReleasePagingIo(IC,FCB) { \
|
|
ASSERT((IC)->CleanupStructure == (FCB)); \
|
|
NtfsReleasePagingResource( IC, FCB ); \
|
|
(IC)->CleanupStructure = NULL; \
|
|
}
|
|
|
|
BOOLEAN
|
|
NtfsAcquireFcbWithPaging (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN ULONG AcquireFlags
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseFcbWithPaging (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseScbWithPaging (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsAcquireExclusiveFcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB Scb OPTIONAL,
|
|
IN ULONG AcquireFlags
|
|
);
|
|
|
|
VOID
|
|
NtfsAcquireSharedFcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB Scb OPTIONAL,
|
|
IN ULONG AcquireFlags
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsAcquireSharedFcbCheckWait (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN ULONG AcquireFlags
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseFcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
VOID
|
|
NtfsAcquireExclusiveScb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
#ifdef NTFSDBG
|
|
|
|
BOOLEAN
|
|
NtfsAcquireResourceExclusive (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
);
|
|
|
|
#else
|
|
|
|
INLINE
|
|
BOOLEAN
|
|
NtfsAcquireResourceExclusive (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
UNREFERENCED_PARAMETER( IrpContext );
|
|
|
|
if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
|
|
Result = ExAcquireResourceExclusiveLite( ((PFCB)FcbOrScb)->Resource, Wait );
|
|
} else {
|
|
Result = ExAcquireResourceExclusiveLite( ((PSCB)(FcbOrScb))->Header.Resource, Wait );
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
#endif
|
|
|
|
INLINE
|
|
BOOLEAN
|
|
NtfsAcquirePagingResourceExclusive (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( IrpContext );
|
|
|
|
if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
|
|
return ExAcquireResourceExclusive( ((PFCB)FcbOrScb)->PagingIoResource, Wait );
|
|
} else {
|
|
return ExAcquireResourceExclusive( ((PSCB)(FcbOrScb))->Header.PagingIoResource, Wait );
|
|
}
|
|
}
|
|
|
|
INLINE
|
|
BOOLEAN
|
|
NtfsAcquirePagingResourceSharedWaitForExclusive (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
UNREFERENCED_PARAMETER( IrpContext );
|
|
|
|
if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
|
|
Result = ExAcquireSharedWaitForExclusive( ((PFCB)FcbOrScb)->PagingIoResource, Wait );
|
|
} else {
|
|
Result = ExAcquireSharedWaitForExclusive( ((PSCB)(FcbOrScb))->Header.PagingIoResource, Wait );
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
INLINE
|
|
BOOLEAN
|
|
NtfsAcquirePagingResourceSharedStarveExclusive (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
UNREFERENCED_PARAMETER( IrpContext );
|
|
|
|
if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
|
|
Result = ExAcquireSharedStarveExclusive( ((PFCB)FcbOrScb)->PagingIoResource, Wait );
|
|
} else {
|
|
Result = ExAcquireSharedStarveExclusive( ((PSCB)(FcbOrScb))->Header.PagingIoResource, Wait );
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
#ifdef NTFSDBG
|
|
|
|
BOOLEAN
|
|
NtfsAcquireResourceShared (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
);
|
|
|
|
|
|
BOOLEAN
|
|
NtfsAcquireResourceSharedWaitForEx (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
);
|
|
|
|
#else
|
|
|
|
INLINE
|
|
BOOLEAN
|
|
NtfsAcquireResourceShared (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
)
|
|
{
|
|
PFCB Fcb;
|
|
|
|
if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
|
|
|
|
Fcb = (PFCB)FcbOrScb;
|
|
|
|
} else {
|
|
|
|
ASSERT_SCB( FcbOrScb );
|
|
|
|
Fcb = ((PSCB)FcbOrScb)->Fcb;
|
|
}
|
|
|
|
return ExAcquireResourceSharedLite( Fcb->Resource, Wait );
|
|
|
|
UNREFERENCED_PARAMETER( IrpContext );
|
|
}
|
|
|
|
INLINE
|
|
BOOLEAN
|
|
NtfsAcquireResourceSharedWaitForEx (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
)
|
|
{
|
|
PFCB Fcb;
|
|
|
|
if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
|
|
|
|
Fcb = (PFCB)FcbOrScb;
|
|
|
|
} else {
|
|
|
|
ASSERT_SCB( FcbOrScb );
|
|
|
|
Fcb = ((PSCB)FcbOrScb)->Fcb;
|
|
|
|
ASSERT( ((PSCB)FcbOrScb)->Header.Resource == Fcb->Resource );
|
|
}
|
|
|
|
return ExAcquireSharedWaitForExclusive( Fcb->Resource, Wait );
|
|
|
|
UNREFERENCED_PARAMETER( IrpContext );
|
|
}
|
|
|
|
#endif
|
|
|
|
INLINE
|
|
BOOLEAN
|
|
NtfsAcquirePagingResourceShared (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb,
|
|
IN BOOLEAN Wait
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
UNREFERENCED_PARAMETER( IrpContext );
|
|
|
|
if (NTFS_NTC_FCB == ((PFCB)FcbOrScb)->NodeTypeCode) {
|
|
Result = ExAcquireResourceShared( ((PFCB)FcbOrScb)->PagingIoResource, Wait );
|
|
} else {
|
|
|
|
ASSERT_SCB( FcbOrScb );
|
|
|
|
Result = ExAcquireResourceShared( ((PSCB)(FcbOrScb))->Header.PagingIoResource, Wait );
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
//
|
|
// VOID
|
|
// NtfsReleaseResource(
|
|
// IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
// IN PVOID FcbOrScb
|
|
// };
|
|
//
|
|
|
|
#ifdef NTFSDBG
|
|
|
|
VOID
|
|
NtfsReleaseResource (
|
|
IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN PVOID FcbOrScb
|
|
);
|
|
|
|
#else
|
|
|
|
#define NtfsReleaseResource( IC, F ) { \
|
|
if (NTFS_NTC_FCB == ((PFCB)(F))->NodeTypeCode) { \
|
|
ExReleaseResourceLite( ((PFCB)(F))->Resource ); \
|
|
} else { \
|
|
ExReleaseResourceLite( ((PSCB)(F))->Header.Resource ); \
|
|
} \
|
|
}
|
|
|
|
#endif
|
|
|
|
#define NtfsReleasePagingResource( IC, F ) { \
|
|
if (NTFS_NTC_FCB == ((PFCB)(F))->NodeTypeCode) { \
|
|
ExReleaseResource( ((PFCB)(F))->PagingIoResource ); \
|
|
} else { \
|
|
ExReleaseResource( ((PSCB)(F))->Header.PagingIoResource ); \
|
|
} \
|
|
}
|
|
|
|
VOID
|
|
NtfsAcquireSharedScbForTransaction (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseSharedResources (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseAllResources (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
VOID
|
|
NtfsAcquireIndexCcb (
|
|
IN PSCB Scb,
|
|
IN PCCB Ccb,
|
|
IN PEOF_WAIT_BLOCK EofWaitBlock
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseIndexCcb (
|
|
IN PSCB Scb,
|
|
IN PCCB Ccb
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// NtfsAcquireSharedScb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PSCB Scb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReleaseScb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PSCB Scb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReleaseGlobal (
|
|
// IN PIRP_CONTEXT IrpContext
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsAcquireFcbTable (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb,
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReleaseFcbTable (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsLockVcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsUnlockVcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsLockFcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsUnlockFcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsAcquireFcbSecurity (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb,
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReleaseFcbSecurity (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsAcquireHashTable (
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReleaseHashTable (
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsAcquireCheckpoint (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb,
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReleaseCheckpoint (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsWaitOnCheckpointNotify (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsSetCheckpointNotify (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsResetCheckpointNotify (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsAcquireReservedClusters (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReleaseReservedClusters (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsAcquireUsnNotify (
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsDeleteUsnNotify (
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
// VOID NtfsAcquireFsrtlHeader (
|
|
// IN PSCB Scb
|
|
// );
|
|
//
|
|
// VOID NtfsReleaseFsrtlHeader (
|
|
// IN PSCB Scb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReleaseVcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
|
|
VOID
|
|
NtfsReleaseVcbCheckDelete (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN UCHAR MajorCode,
|
|
IN PFILE_OBJECT FileObject OPTIONAL
|
|
);
|
|
|
|
#define NtfsAcquireSharedScb(IC,S) { \
|
|
NtfsAcquireSharedFcb((IC),(S)->Fcb, S, 0); \
|
|
}
|
|
|
|
#define NtfsAcquireSharedScbWaitForEx(IC,S) \
|
|
NtfsAcquireResourceSharedWaitForEx( IC, S, BooleanFlagOn( (IC)->State, IRP_CONTEXT_STATE_WAIT ) )
|
|
|
|
|
|
#define NtfsReleaseScb(IC,S) { \
|
|
NtfsReleaseFcb((IC),(S)->Fcb); \
|
|
}
|
|
|
|
#define NtfsReleaseGlobal(IC) { \
|
|
ExReleaseResourceLite( &NtfsData.Resource ); \
|
|
}
|
|
|
|
#define NtfsAcquireFcbTable(IC,V) { \
|
|
ExAcquireFastMutexUnsafe( &(V)->FcbTableMutex ); \
|
|
}
|
|
|
|
#define NtfsReleaseFcbTable(IC,V) { \
|
|
ExReleaseFastMutexUnsafe( &(V)->FcbTableMutex ); \
|
|
}
|
|
|
|
#define NtfsLockVcb(IC,V) { \
|
|
ExAcquireFastMutexUnsafe( &(V)->FcbSecurityMutex ); \
|
|
}
|
|
|
|
#define NtfsUnlockVcb(IC,V) { \
|
|
ExReleaseFastMutexUnsafe( &(V)->FcbSecurityMutex ); \
|
|
}
|
|
|
|
#define NtfsLockFcb(IC,F) { \
|
|
ExAcquireFastMutex( (F)->FcbMutex ); \
|
|
}
|
|
|
|
#define NtfsUnlockFcb(IC,F) { \
|
|
ExReleaseFastMutex( (F)->FcbMutex ); \
|
|
}
|
|
|
|
#define NtfsAcquireFcbSecurity(V) { \
|
|
ExAcquireFastMutexUnsafe( &(V)->FcbSecurityMutex ); \
|
|
}
|
|
|
|
#define NtfsReleaseFcbSecurity(V) { \
|
|
ExReleaseFastMutexUnsafe( &(V)->FcbSecurityMutex ); \
|
|
}
|
|
|
|
#define NtfsAcquireHashTable(V) { \
|
|
ExAcquireFastMutexUnsafe( &(V)->HashTableMutex ); \
|
|
}
|
|
|
|
#define NtfsReleaseHashTable(V) { \
|
|
ExReleaseFastMutexUnsafe( &(V)->HashTableMutex ); \
|
|
}
|
|
|
|
#define NtfsAcquireCheckpoint(IC,V) { \
|
|
ExAcquireFastMutexUnsafe( &(V)->CheckpointMutex ); \
|
|
}
|
|
|
|
#define NtfsReleaseCheckpoint(IC,V) { \
|
|
ExReleaseFastMutexUnsafe( &(V)->CheckpointMutex ); \
|
|
}
|
|
|
|
#define NtfsWaitOnCheckpointNotify(IC,V) { \
|
|
NTSTATUS _Status; \
|
|
_Status = KeWaitForSingleObject( &(V)->CheckpointNotifyEvent, \
|
|
Executive, \
|
|
KernelMode, \
|
|
FALSE, \
|
|
NULL ); \
|
|
if (!NT_SUCCESS( _Status )) { \
|
|
NtfsRaiseStatus( IrpContext, _Status, NULL, NULL ); \
|
|
} \
|
|
}
|
|
|
|
#define NtfsSetCheckpointNotify(IC,V) { \
|
|
(V)->CheckpointOwnerThread = NULL; \
|
|
KeSetEvent( &(V)->CheckpointNotifyEvent, 0, FALSE ); \
|
|
}
|
|
|
|
#define NtfsResetCheckpointNotify(IC,V) { \
|
|
(V)->CheckpointOwnerThread = (PVOID) PsGetCurrentThread(); \
|
|
KeClearEvent( &(V)->CheckpointNotifyEvent ); \
|
|
}
|
|
|
|
#define NtfsAcquireUsnNotify(V) { \
|
|
ExAcquireFastMutex( &(V)->CheckpointMutex ); \
|
|
}
|
|
|
|
#define NtfsReleaseUsnNotify(V) { \
|
|
ExReleaseFastMutex( &(V)->CheckpointMutex ); \
|
|
}
|
|
|
|
#define NtfsAcquireReservedClusters(V) { \
|
|
ExAcquireFastMutexUnsafe( &(V)->ReservedClustersMutex );\
|
|
}
|
|
|
|
#define NtfsReleaseReservedClusters(V) { \
|
|
ExReleaseFastMutexUnsafe( &(V)->ReservedClustersMutex );\
|
|
}
|
|
|
|
#define NtfsAcquireFsrtlHeader(S) { \
|
|
ExAcquireFastMutex((S)->Header.FastMutex); \
|
|
}
|
|
|
|
#define NtfsReleaseFsrtlHeader(S) { \
|
|
ExReleaseFastMutex((S)->Header.FastMutex); \
|
|
}
|
|
|
|
#ifdef NTFSDBG
|
|
|
|
VOID NtfsReleaseVcb(
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
#else
|
|
|
|
#define NtfsReleaseVcb(IC,V) { \
|
|
ExReleaseResourceLite( &(V)->Resource ); \
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Macros to test resources for exclusivity.
|
|
//
|
|
|
|
#define NtfsIsExclusiveResource(R) ( \
|
|
ExIsResourceAcquiredExclusiveLite(R) \
|
|
)
|
|
|
|
#define NtfsIsExclusiveFcb(F) ( \
|
|
(NtfsIsExclusiveResource((F)->Resource)) \
|
|
)
|
|
|
|
#define NtfsIsExclusiveFcbPagingIo(F) ( \
|
|
(NtfsIsExclusiveResource((F)->PagingIoResource)) \
|
|
)
|
|
|
|
#define NtfsIsExclusiveScbPagingIo(S) ( \
|
|
(NtfsIsExclusiveFcbPagingIo((S)->Fcb)) \
|
|
)
|
|
|
|
#define NtfsIsExclusiveScb(S) ( \
|
|
(NtfsIsExclusiveFcb((S)->Fcb)) \
|
|
)
|
|
|
|
#define NtfsIsExclusiveVcb(V) ( \
|
|
(NtfsIsExclusiveResource(&(V)->Resource)) \
|
|
)
|
|
|
|
//
|
|
// Macros to test resources for shared acquire
|
|
//
|
|
|
|
#define NtfsIsSharedResource(R) ( \
|
|
ExIsResourceAcquiredSharedLite(R) \
|
|
)
|
|
|
|
#define NtfsIsSharedFcb(F) ( \
|
|
(NtfsIsSharedResource((F)->Resource)) \
|
|
)
|
|
|
|
#define NtfsIsSharedFcbPagingIo(F) ( \
|
|
(NtfsIsSharedResource((F)->PagingIoResource)) \
|
|
)
|
|
|
|
#define NtfsIsSharedScbPagingIo(S) ( \
|
|
(NtfsIsSharedFcbPagingIo((S)->Fcb)) \
|
|
)
|
|
|
|
#define NtfsIsSharedScb(S) ( \
|
|
(NtfsIsSharedFcb((S)->Fcb)) \
|
|
)
|
|
|
|
#define NtfsIsSharedVcb(V) ( \
|
|
(NtfsIsSharedResource(&(V)->Resource)) \
|
|
)
|
|
|
|
__inline
|
|
VOID
|
|
NtfsReleaseExclusiveScbIfOwned(
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called release an Scb that may or may not be currently
|
|
owned exclusive.
|
|
|
|
Arguments:
|
|
|
|
IrpContext - Context of call
|
|
|
|
Scb - Scb to be released
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
if (Scb->Fcb->ExclusiveFcbLinks.Flink != NULL &&
|
|
NtfsIsExclusiveScb( Scb )) {
|
|
|
|
NtfsReleaseScb( IrpContext, Scb );
|
|
}
|
|
}
|
|
|
|
//
|
|
// The following are cache manager call backs. They return FALSE
|
|
// if the resource cannot be acquired with waiting and wait is false.
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsAcquireScbForLazyWrite (
|
|
IN PVOID Null,
|
|
IN BOOLEAN Wait
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseScbFromLazyWrite (
|
|
IN PVOID Null
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsAcquireFileForModWrite (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER EndingOffset,
|
|
OUT PERESOURCE *ResourceToRelease,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsAcquireFileForCcFlush (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsReleaseFileForCcFlush (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
VOID
|
|
NtfsAcquireForCreateSection (
|
|
IN PFILE_OBJECT FileObject
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseForCreateSection (
|
|
IN PFILE_OBJECT FileObject
|
|
);
|
|
|
|
|
|
BOOLEAN
|
|
NtfsAcquireScbForReadAhead (
|
|
IN PVOID Null,
|
|
IN BOOLEAN Wait
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseScbFromReadAhead (
|
|
IN PVOID Null
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsAcquireVolumeFileForLazyWrite (
|
|
IN PVOID Vcb,
|
|
IN BOOLEAN Wait
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseVolumeFileFromLazyWrite (
|
|
IN PVOID Vcb
|
|
);
|
|
|
|
|
|
//
|
|
// Ntfs Logging Routine interfaces in RestrSup.c
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsRestartVolume (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
OUT PBOOLEAN UnrecognizedRestart
|
|
);
|
|
|
|
VOID
|
|
NtfsAbortTransaction (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PTRANSACTION_ENTRY Transaction OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCloseAttributesFromRestart (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
|
|
//
|
|
// Security support routines, implemented in SecurSup.c
|
|
//
|
|
|
|
//
|
|
// VOID
|
|
// NtfsTraverseCheck (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB ParentFcb,
|
|
// IN PIRP Irp
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsOpenCheck (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN PFCB ParentFcb OPTIONAL,
|
|
// IN PIRP Irp
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsCreateCheck (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB ParentFcb,
|
|
// IN PIRP Irp
|
|
// );
|
|
//
|
|
|
|
#define NtfsTraverseCheck(IC,F,IR) { \
|
|
NtfsAccessCheck( IC, \
|
|
F, \
|
|
NULL, \
|
|
IR, \
|
|
FILE_TRAVERSE, \
|
|
TRUE ); \
|
|
}
|
|
|
|
#define NtfsOpenCheck(IC,F,PF,IR) { \
|
|
NtfsAccessCheck( IC, \
|
|
F, \
|
|
PF, \
|
|
IR, \
|
|
IoGetCurrentIrpStackLocation(IR)->Parameters.Create.SecurityContext->DesiredAccess, \
|
|
FALSE ); \
|
|
}
|
|
|
|
#define NtfsCreateCheck(IC,PF,IR) { \
|
|
NtfsAccessCheck( IC, \
|
|
PF, \
|
|
NULL, \
|
|
IR, \
|
|
(FlagOn(IoGetCurrentIrpStackLocation(IR)->Parameters.Create.Options, FILE_DIRECTORY_FILE) ? \
|
|
FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE), \
|
|
TRUE ); \
|
|
}
|
|
|
|
VOID
|
|
NtfsAssignSecurity (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB ParentFcb,
|
|
IN PIRP Irp,
|
|
IN PFCB NewFcb,
|
|
IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
|
|
IN PBCB FileRecordBcb,
|
|
IN LONGLONG FileOffset,
|
|
IN OUT PBOOLEAN LogIt
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsModifySecurity (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSECURITY_INFORMATION SecurityInformation,
|
|
OUT PSECURITY_DESCRIPTOR SecurityDescriptor
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsQuerySecurity (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSECURITY_INFORMATION SecurityInformation,
|
|
OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
IN OUT PULONG SecurityDescriptorLength
|
|
);
|
|
|
|
VOID
|
|
NtfsAccessCheck (
|
|
PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PFCB ParentFcb OPTIONAL,
|
|
IN PIRP Irp,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN BOOLEAN CheckOnly
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCanAdministerVolume (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN PSECURITY_DESCRIPTOR TestSecurityDescriptor OPTIONAL,
|
|
IN PULONG TestDesiredAccess OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCheckFileForDelete (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB ParentScb,
|
|
IN PFCB ThisFcb,
|
|
IN BOOLEAN FcbExisted,
|
|
IN PINDEX_ENTRY IndexEntry
|
|
);
|
|
|
|
VOID
|
|
NtfsCheckIndexForAddOrDelete (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB ParentFcb,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN ULONG CreatePrivileges
|
|
);
|
|
|
|
VOID
|
|
NtfsSetFcbSecurityFromDescriptor (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PFCB Fcb,
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
IN ULONG SecurityDescriptorLength,
|
|
IN BOOLEAN RaiseIfInvalid
|
|
);
|
|
|
|
INLINE
|
|
VOID
|
|
RemoveReferenceSharedSecurityUnsafe (
|
|
IN OUT PSHARED_SECURITY *SharedSecurity
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to manage the reference count on a shared security
|
|
descriptor. If the reference count goes to zero, the shared security is
|
|
freed.
|
|
|
|
Arguments:
|
|
|
|
SharedSecurity - security that is being dereferenced.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DebugTrace( 0, (DEBUG_TRACE_SECURSUP | DEBUG_TRACE_ACLINDEX),
|
|
( "RemoveReferenceSharedSecurityUnsafe( %08x )\n", *SharedSecurity ));
|
|
//
|
|
// Note that there will be one less reference shortly
|
|
//
|
|
|
|
ASSERT( (*SharedSecurity)->ReferenceCount != 0 );
|
|
|
|
(*SharedSecurity)->ReferenceCount--;
|
|
|
|
if ((*SharedSecurity)->ReferenceCount == 0) {
|
|
DebugTrace( 0, (DEBUG_TRACE_SECURSUP | DEBUG_TRACE_ACLINDEX),
|
|
( "RemoveReferenceSharedSecurityUnsafe freeing\n" ));
|
|
NtfsFreePool( *SharedSecurity );
|
|
}
|
|
*SharedSecurity = NULL;
|
|
}
|
|
|
|
BOOLEAN
|
|
NtfsNotifyTraverseCheck (
|
|
IN PCCB Ccb,
|
|
IN PFCB Fcb,
|
|
IN PSECURITY_SUBJECT_CONTEXT SubjectContext
|
|
);
|
|
|
|
VOID
|
|
NtfsLoadSecurityDescriptor (
|
|
PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
VOID
|
|
NtfsStoreSecurityDescriptor (
|
|
PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN BOOLEAN LogIt
|
|
);
|
|
|
|
VOID
|
|
NtfsInitializeSecurity (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
VOID
|
|
NtOfsPurgeSecurityCache (
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
PSHARED_SECURITY
|
|
NtfsCacheSharedSecurityBySecurityId (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN SECURITY_ID SecurityId
|
|
);
|
|
|
|
PSHARED_SECURITY
|
|
NtfsCacheSharedSecurityForCreate (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB ParentFcb
|
|
);
|
|
|
|
SECURITY_ID
|
|
GetSecurityIdFromSecurityDescriptorUnsafe (
|
|
PIRP_CONTEXT IrpContext,
|
|
IN OUT PSHARED_SECURITY SharedSecurity
|
|
);
|
|
|
|
FSRTL_COMPARISON_RESULT
|
|
NtOfsCollateSecurityHash (
|
|
IN PINDEX_KEY Key1,
|
|
IN PINDEX_KEY Key2,
|
|
IN PVOID CollationData
|
|
);
|
|
|
|
#ifdef NTFS_CACHE_RIGHTS
|
|
VOID
|
|
NtfsGetCachedRightsById (
|
|
IN PVCB Vcb,
|
|
IN PLUID TokenId,
|
|
IN PLUID ModifiedId,
|
|
IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
|
|
IN PSHARED_SECURITY SharedSecurity,
|
|
OUT PBOOLEAN EntryCached OPTIONAL,
|
|
OUT PACCESS_MASK Rights
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsGetCachedRights (
|
|
IN PVCB Vcb,
|
|
IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
|
|
IN PSHARED_SECURITY SharedSecurity,
|
|
OUT PACCESS_MASK Rights,
|
|
OUT PBOOLEAN EntryCached OPTIONAL,
|
|
OUT PLUID TokenId OPTIONAL,
|
|
OUT PLUID ModifiedId OPTIONAL
|
|
);
|
|
#endif
|
|
|
|
|
|
//
|
|
// In-memory structure support routine, implemented in StrucSup.c
|
|
//
|
|
|
|
//
|
|
// Routines to create and destroy the Vcb
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeVcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PVCB Vcb,
|
|
IN PDEVICE_OBJECT TargetDeviceObject,
|
|
IN PVPB Vpb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsDeleteVcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PVCB *Vcb
|
|
);
|
|
|
|
//
|
|
// Routines to create and destroy the Fcb
|
|
//
|
|
|
|
PFCB
|
|
NtfsCreateRootFcb ( // also creates the root lcb
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
PFCB
|
|
NtfsCreateFcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN FILE_REFERENCE FileReference,
|
|
IN BOOLEAN IsPagingFile,
|
|
IN BOOLEAN LargeFcb,
|
|
OUT PBOOLEAN ReturnedExistingFcb OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteFcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PFCB *Fcb,
|
|
OUT PBOOLEAN AcquiredFcbTable
|
|
);
|
|
|
|
PFCB
|
|
NtfsGetNextFcbTableEntry (
|
|
IN PVCB Vcb,
|
|
IN PVOID *RestartKey
|
|
);
|
|
|
|
//
|
|
// Routines to create and destroy the Scb
|
|
//
|
|
|
|
PSCB
|
|
NtfsCreateScb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
|
|
IN PCUNICODE_STRING AttributeName,
|
|
IN BOOLEAN ReturnExistingOnly,
|
|
OUT PBOOLEAN ReturnedExistingScb OPTIONAL
|
|
);
|
|
|
|
PSCB
|
|
NtfsCreatePrerestartScb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFILE_REFERENCE FileReference,
|
|
IN ATTRIBUTE_TYPE_CODE AttributeTypeCode,
|
|
IN PUNICODE_STRING AttributeName OPTIONAL,
|
|
IN ULONG BytesPerIndexBuffer
|
|
);
|
|
|
|
VOID
|
|
NtfsFreeScbAttributeName (
|
|
IN PWSTR AttributeNameBuffer
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteScb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PSCB *Scb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsUpdateNormalizedName (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB ParentScb,
|
|
IN PSCB Scb,
|
|
IN PFILE_NAME FileName OPTIONAL,
|
|
IN BOOLEAN CheckBufferSizeOnly,
|
|
IN BOOLEAN NewDirectory
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteNormalizedName (
|
|
IN PSCB Scb
|
|
);
|
|
|
|
typedef
|
|
NTSTATUS
|
|
(*NTFSWALKUPFUNCTION)(
|
|
PIRP_CONTEXT IrpContext,
|
|
PFCB Fcb,
|
|
PSCB Scb,
|
|
PFILE_NAME FileName,
|
|
PVOID Context );
|
|
|
|
NTSTATUS
|
|
NtfsWalkUpTree (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN NTFSWALKUPFUNCTION WalkUpFunction,
|
|
IN OUT PVOID Context
|
|
);
|
|
|
|
typedef struct {
|
|
UNICODE_STRING Name;
|
|
FILE_REFERENCE Scope;
|
|
BOOLEAN IsRoot;
|
|
#ifdef BENL_DBG
|
|
PFCB StartFcb;
|
|
#endif
|
|
} SCOPE_CONTEXT, *PSCOPE_CONTEXT;
|
|
|
|
NTSTATUS
|
|
NtfsBuildRelativeName (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB Scb,
|
|
IN PFILE_NAME FileName,
|
|
IN OUT PVOID Context
|
|
);
|
|
|
|
VOID
|
|
NtfsBuildNormalizedName (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB IndexScb OPTIONAL,
|
|
OUT PUNICODE_STRING FileName
|
|
);
|
|
|
|
VOID
|
|
NtfsSnapshotScb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateScbSnapshots (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
VOID
|
|
NtfsRestoreScbSnapshots (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN BOOLEAN Higher
|
|
);
|
|
|
|
VOID
|
|
NtfsMungeScbSnapshot (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN LONGLONG FileSize
|
|
);
|
|
|
|
VOID
|
|
NtfsFreeSnapshotsForFcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCreateFileLock (
|
|
IN PSCB Scb,
|
|
IN BOOLEAN RaiseOnError
|
|
);
|
|
|
|
//
|
|
//
|
|
// A general purpose teardown routine that helps cleanup the
|
|
// the Fcb/Scb structures
|
|
//
|
|
|
|
VOID
|
|
NtfsTeardownStructures (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVOID FcbOrScb,
|
|
IN PLCB Lcb OPTIONAL,
|
|
IN BOOLEAN CheckForAttributeTable,
|
|
IN ULONG AcquireFlags,
|
|
OUT PBOOLEAN RemovedFcb OPTIONAL
|
|
);
|
|
|
|
//
|
|
// Routines to create, destroy and walk through the Lcbs
|
|
//
|
|
|
|
PLCB
|
|
NtfsCreateLcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PFCB Fcb,
|
|
IN UNICODE_STRING LastComponentFileName,
|
|
IN UCHAR FileNameFlags,
|
|
IN OUT PBOOLEAN ReturnedExistingLcb OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteLcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN OUT PLCB *Lcb
|
|
);
|
|
|
|
VOID
|
|
NtfsMoveLcb ( // also munges the ccb and fileobjects filenames
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PLCB Lcb,
|
|
IN PSCB Scb,
|
|
IN PFCB Fcb,
|
|
IN PUNICODE_STRING TargetDirectoryName,
|
|
IN PUNICODE_STRING LastComponentName,
|
|
IN UCHAR FileNameFlags,
|
|
IN BOOLEAN CheckBufferSizeOnly
|
|
);
|
|
|
|
VOID
|
|
NtfsRenameLcb ( // also munges the ccb and fileobjects filenames
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PLCB Lcb,
|
|
IN PUNICODE_STRING LastComponentFileName,
|
|
IN UCHAR FileNameFlags,
|
|
IN BOOLEAN CheckBufferSizeOnly
|
|
);
|
|
|
|
VOID
|
|
NtfsCombineLcbs (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PLCB PrimaryLcb,
|
|
IN PLCB AuxLcb
|
|
);
|
|
|
|
PLCB
|
|
NtfsLookupLcbByFlags (
|
|
IN PFCB Fcb,
|
|
IN UCHAR FileNameFlags
|
|
);
|
|
|
|
ULONG
|
|
NtfsLookupNameLengthViaLcb (
|
|
IN PFCB Fcb,
|
|
OUT PBOOLEAN LeadingBackslash
|
|
);
|
|
|
|
VOID
|
|
NtfsFileNameViaLcb (
|
|
IN PFCB Fcb,
|
|
IN PWCHAR FileName,
|
|
ULONG Length,
|
|
ULONG BytesToCopy
|
|
);
|
|
|
|
//
|
|
// VOID
|
|
// NtfsLinkCcbToLcb (
|
|
// IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
// IN PFCB Fcb,
|
|
// IN PCCB Ccb,
|
|
// IN PLCB Lcb
|
|
// );
|
|
//
|
|
|
|
#define NtfsLinkCcbToLcb(IC,F,C,L) { \
|
|
NtfsLockFcb( IC, F ); \
|
|
InsertTailList( &(L)->CcbQueue, &(C)->LcbLinks ); \
|
|
(C)->Lcb = (L); \
|
|
NtfsUnlockFcb( IC, F ); \
|
|
}
|
|
|
|
//
|
|
// VOID
|
|
// NtfsUnlinkCcbFromLcb (
|
|
// IN PIRP_CONTEXT IrpContext OPTIONAL,
|
|
// IN PFCB Fcb,
|
|
// IN PCCB Ccb
|
|
// );
|
|
//
|
|
|
|
#define NtfsUnlinkCcbFromLcb(IC,F,C) { \
|
|
NtfsLockFcb( IC, F ); \
|
|
if ((C)->Lcb != NULL) { \
|
|
RemoveEntryList( &(C)->LcbLinks ); \
|
|
(C)->Lcb = NULL; \
|
|
} \
|
|
NtfsUnlockFcb( IC, F ); \
|
|
}
|
|
|
|
//
|
|
// Routines to create and destroy the Ccb
|
|
//
|
|
|
|
PCCB
|
|
NtfsCreateCcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB Scb,
|
|
IN BOOLEAN Indexed,
|
|
IN USHORT EaModificationCount,
|
|
IN ULONG Flags,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONG LastFileNameOffset
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteCcb (
|
|
IN PFCB Fcb,
|
|
IN OUT PCCB *Ccb
|
|
);
|
|
|
|
//
|
|
// Routines to create and destroy the IrpContext
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeIrpContext (
|
|
IN PIRP Irp OPTIONAL,
|
|
IN BOOLEAN Wait,
|
|
IN OUT PIRP_CONTEXT *IrpContext
|
|
);
|
|
|
|
VOID
|
|
NtfsCleanupIrpContext (
|
|
IN OUT PIRP_CONTEXT IrpContext,
|
|
IN ULONG Retry
|
|
);
|
|
|
|
//
|
|
// Routines to initialize and change the ntfs_io_context
|
|
//
|
|
|
|
VOID
|
|
NtfsInitializeIoContext (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PNTFS_IO_CONTEXT IoContext,
|
|
IN BOOLEAN PagingIo
|
|
);
|
|
|
|
VOID
|
|
NtfsSetIoContextAsync (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PERESOURCE ResourceToRelease,
|
|
IN ULONG ByteCount
|
|
);
|
|
|
|
|
|
//
|
|
// Routine for scanning the Fcbs within the graph hierarchy
|
|
//
|
|
|
|
PSCB
|
|
NtfsGetNextScb (
|
|
IN PSCB Scb,
|
|
IN PSCB TerminationScb
|
|
);
|
|
|
|
//
|
|
// The following macros are useful for traversing the queues interconnecting
|
|
// fcbs, scb, and lcbs.
|
|
//
|
|
// PSCB
|
|
// NtfsGetNextChildScb (
|
|
// IN PFCB Fcb,
|
|
// IN PSCB PreviousChildScb
|
|
// );
|
|
//
|
|
// PLCB
|
|
// NtfsGetNextParentLcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN PLCB PreviousParentLcb
|
|
// );
|
|
//
|
|
// PLCB
|
|
// NtfsGetNextChildLcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PSCB Scb,
|
|
// IN PLCB PreviousChildLcb
|
|
// );
|
|
//
|
|
// PLCB
|
|
// NtfsGetPrevChildLcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PSCB Scb,
|
|
// IN PLCB PreviousChildLcb
|
|
// );
|
|
//
|
|
// PLCB
|
|
// NtfsGetNextParentLcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PFCB Fcb,
|
|
// IN PLCB PreviousChildLcb
|
|
// );
|
|
//
|
|
// PCCB
|
|
// NtfsGetNextCcb (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PLCB Lcb,
|
|
// IN PCCB PreviousCcb
|
|
// );
|
|
//
|
|
|
|
#define NtfsGetNextChildScb(F,P) ((PSCB) \
|
|
((P) == NULL ? \
|
|
(IsListEmpty(&(F)->ScbQueue) ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD((F)->ScbQueue.Flink, SCB, FcbLinks.Flink) \
|
|
) \
|
|
: \
|
|
((PVOID)((PSCB)(P))->FcbLinks.Flink == &(F)->ScbQueue.Flink ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD(((PSCB)(P))->FcbLinks.Flink, SCB, FcbLinks.Flink) \
|
|
) \
|
|
) \
|
|
)
|
|
|
|
#define NtfsGetNextParentLcb(F,P) ((PLCB) \
|
|
((P) == NULL ? \
|
|
(IsListEmpty(&(F)->LcbQueue) ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD((F)->LcbQueue.Flink, LCB, FcbLinks.Flink) \
|
|
) \
|
|
: \
|
|
((PVOID)((PLCB)(P))->FcbLinks.Flink == &(F)->LcbQueue.Flink ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD(((PLCB)(P))->FcbLinks.Flink, LCB, FcbLinks.Flink) \
|
|
) \
|
|
) \
|
|
)
|
|
|
|
#define NtfsGetNextChildLcb(S,P) ((PLCB) \
|
|
((P) == NULL ? \
|
|
((((NodeType(S) == NTFS_NTC_SCB_DATA) || (NodeType(S) == NTFS_NTC_SCB_MFT)) \
|
|
|| IsListEmpty(&(S)->ScbType.Index.LcbQueue)) ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD((S)->ScbType.Index.LcbQueue.Flink, LCB, ScbLinks.Flink) \
|
|
) \
|
|
: \
|
|
((PVOID)((PLCB)(P))->ScbLinks.Flink == &(S)->ScbType.Index.LcbQueue.Flink ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD(((PLCB)(P))->ScbLinks.Flink, LCB, ScbLinks.Flink) \
|
|
) \
|
|
) \
|
|
)
|
|
|
|
#define NtfsGetPrevChildLcb(S,P) ((PLCB) \
|
|
((P) == NULL ? \
|
|
((((NodeType(S) == NTFS_NTC_SCB_DATA) || (NodeType(S) == NTFS_NTC_SCB_MFT)) \
|
|
|| IsListEmpty(&(S)->ScbType.Index.LcbQueue)) ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD((S)->ScbType.Index.LcbQueue.Blink, LCB, ScbLinks.Flink) \
|
|
) \
|
|
: \
|
|
((PVOID)((PLCB)(P))->ScbLinks.Blink == &(S)->ScbType.Index.LcbQueue.Flink ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD(((PLCB)(P))->ScbLinks.Blink, LCB, ScbLinks.Flink) \
|
|
) \
|
|
) \
|
|
)
|
|
|
|
#define NtfsGetNextParentLcb(F,P) ((PLCB) \
|
|
((P) == NULL ? \
|
|
(IsListEmpty(&(F)->LcbQueue) ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD((F)->LcbQueue.Flink, LCB, FcbLinks.Flink) \
|
|
) \
|
|
: \
|
|
((PVOID)((PLCB)(P))->FcbLinks.Flink == &(F)->LcbQueue.Flink ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD(((PLCB)(P))->FcbLinks.Flink, LCB, FcbLinks.Flink) \
|
|
) \
|
|
) \
|
|
)
|
|
|
|
#define NtfsGetNextCcb(L,P) ((PCCB) \
|
|
((P) == NULL ? \
|
|
(IsListEmpty(&(L)->CcbQueue) ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD((L)->CcbQueue.Flink, CCB, LcbLinks.Flink) \
|
|
) \
|
|
: \
|
|
((PVOID)((PCCB)(P))->LcbLinks.Flink == &(L)->CcbQueue.Flink ? \
|
|
NULL \
|
|
: \
|
|
CONTAINING_RECORD(((PCCB)(P))->LcbLinks.Flink, CCB, LcbLinks.Flink) \
|
|
) \
|
|
) \
|
|
)
|
|
|
|
|
|
#define NtfsGetFirstCcbEntry(S) \
|
|
(IsListEmpty( &(S)->CcbQueue ) \
|
|
? NULL \
|
|
: CONTAINING_RECORD( (S)->CcbQueue.Flink, CCB, CcbLinks.Flink ))
|
|
|
|
#define NtfsGetNextCcbEntry(S,C) \
|
|
( (PVOID)&(S)->CcbQueue.Flink == (PVOID)(C)->CcbLinks.Flink \
|
|
? NULL \
|
|
: CONTAINING_RECORD( (C)->CcbLinks.Flink, CCB, CcbLinks.Flink ))
|
|
|
|
|
|
//
|
|
// VOID
|
|
// NtfsDeleteFcbTableEntry (
|
|
// IN PVCB Vcb,
|
|
// IN FILE_REFERENCE FileReference
|
|
// );
|
|
//
|
|
|
|
#if (defined( NTFS_FREE_ASSERTS ))
|
|
#define NtfsDeleteFcbTableEntry(V,FR) { \
|
|
FCB_TABLE_ELEMENT _Key; \
|
|
BOOLEAN _RemovedEntry; \
|
|
_Key.FileReference = FR; \
|
|
_RemovedEntry = RtlDeleteElementGenericTable( &(V)->FcbTable, &_Key ); \
|
|
ASSERT( _RemovedEntry ); \
|
|
}
|
|
#else
|
|
#define NtfsDeleteFcbTableEntry(V,FR) { \
|
|
FCB_TABLE_ELEMENT _Key; \
|
|
_Key.FileReference = FR; \
|
|
RtlDeleteElementGenericTable( &(V)->FcbTable, &_Key ); \
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Routines for allocating and deallocating the compression synchronization structures.
|
|
//
|
|
|
|
PVOID
|
|
NtfsAllocateCompressionSync (
|
|
IN POOL_TYPE PoolType,
|
|
IN SIZE_T NumberOfBytes,
|
|
IN ULONG Tag
|
|
);
|
|
|
|
VOID
|
|
NtfsDeallocateCompressionSync (
|
|
IN PVOID CompressionSync
|
|
);
|
|
|
|
//
|
|
// The following four routines are for incrementing and decrementing the cleanup
|
|
// counts and the close counts. In all of the structures
|
|
//
|
|
|
|
VOID
|
|
NtfsIncrementCleanupCounts (
|
|
IN PSCB Scb,
|
|
IN PLCB Lcb OPTIONAL,
|
|
IN BOOLEAN NonCachedHandle
|
|
);
|
|
|
|
VOID
|
|
NtfsIncrementCloseCounts (
|
|
IN PSCB Scb,
|
|
IN BOOLEAN SystemFile,
|
|
IN BOOLEAN ReadOnly
|
|
);
|
|
|
|
VOID
|
|
NtfsDecrementCleanupCounts (
|
|
IN PSCB Scb,
|
|
IN PLCB Lcb OPTIONAL,
|
|
IN BOOLEAN NonCachedHandle
|
|
);
|
|
|
|
VOID
|
|
NtfsDecrementCloseCounts (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PLCB Lcb OPTIONAL,
|
|
IN BOOLEAN SystemFile,
|
|
IN BOOLEAN ReadOnly,
|
|
IN BOOLEAN DecrementCountsOnly,
|
|
IN OUT PBOOLEAN RemovedFcb OPTIONAL
|
|
);
|
|
|
|
PERESOURCE
|
|
NtfsAllocateEresource (
|
|
);
|
|
|
|
VOID
|
|
NtfsFreeEresource (
|
|
IN PERESOURCE Eresource
|
|
);
|
|
|
|
PVOID
|
|
NtfsAllocateFcbTableEntry (
|
|
IN PRTL_GENERIC_TABLE FcbTable,
|
|
IN CLONG ByteSize
|
|
);
|
|
|
|
VOID
|
|
NtfsFreeFcbTableEntry (
|
|
IN PRTL_GENERIC_TABLE FcbTable,
|
|
IN PVOID Buffer
|
|
);
|
|
|
|
VOID
|
|
NtfsPostToNewLengthQueue (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
VOID
|
|
NtfsProcessNewLengthQueue (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN BOOLEAN CleanupOnly
|
|
);
|
|
|
|
//
|
|
// Useful debug routines
|
|
//
|
|
|
|
VOID
|
|
NtfsTestStatusProc (
|
|
);
|
|
|
|
//
|
|
// Usn Support routines in UsnSup.c
|
|
//
|
|
|
|
NTSTATUS
|
|
NtfsReadUsnJournal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN BOOLEAN ProbeInput
|
|
);
|
|
|
|
ULONG
|
|
NtfsPostUsnChange (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVOID ScborFcb,
|
|
IN ULONG Reason
|
|
);
|
|
|
|
VOID
|
|
NtfsWriteUsnJournalChanges (
|
|
PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
VOID
|
|
NtfsSetupUsnJournal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFCB Fcb,
|
|
IN ULONG CreateIfNotExist,
|
|
IN ULONG Restamp,
|
|
IN PCREATE_USN_JOURNAL_DATA JournalData
|
|
);
|
|
|
|
VOID
|
|
NtfsTrimUsnJournal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsQueryUsnJournal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsDeleteUsnJournal (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
NtfsDeleteUsnSpecial (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVOID Context
|
|
);
|
|
|
|
//
|
|
// NtOfs support routines in vattrsup.c
|
|
//
|
|
|
|
NTFSAPI
|
|
NTSTATUS
|
|
NtfsHoldIrpForNewLength (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PIRP Irp,
|
|
IN LONGLONG Length,
|
|
IN PDRIVER_CANCEL CancelRoutine,
|
|
IN PVOID CapturedData OPTIONAL,
|
|
OUT PVOID *CopyCapturedData OPTIONAL,
|
|
IN ULONG CapturedDataLength
|
|
);
|
|
|
|
|
|
//
|
|
// Time conversion support routines, implemented as a macro
|
|
//
|
|
// VOID
|
|
// NtfsGetCurrentTime (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN LONGLONG Time
|
|
// );
|
|
//
|
|
|
|
#define NtfsGetCurrentTime(_IC,_T) { \
|
|
ASSERT_IRP_CONTEXT(_IC); \
|
|
KeQuerySystemTime((PLARGE_INTEGER)&(_T)); \
|
|
}
|
|
|
|
//
|
|
// Time routine to check if last access should be updated.
|
|
//
|
|
// BOOLEAN
|
|
// NtfsCheckLastAccess (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN OUT PFCB Fcb
|
|
// );
|
|
//
|
|
|
|
#define NtfsCheckLastAccess(_IC,_FCB) ( \
|
|
((NtfsLastAccess + (_FCB)->Info.LastAccessTime) < (_FCB)->CurrentLastAccess) || \
|
|
((_FCB)->CurrentLastAccess < (_FCB)->Info.LastAccessTime) \
|
|
)
|
|
|
|
|
|
//
|
|
// Macro and #defines to decide whether a given feature is supported on a
|
|
// given volume version. Currently, all features either work on all Ntfs
|
|
// volumes, or work on all volumes with major version greater than 1. In
|
|
// some future version, some features may require version 4.x volumes, etc.
|
|
//
|
|
// This macro is used to decide whether to fail a user request with
|
|
// STATUS_VOLUME_NOT_UPGRADED, and also helps us set the FILE_SUPPORTS_xxx
|
|
// flags correctly in NtfsQueryFsAttributeInfo.
|
|
//
|
|
|
|
#define NTFS_ENCRYPTION_VERSION 2
|
|
#define NTFS_OBJECT_ID_VERSION 2
|
|
#define NTFS_QUOTA_VERSION 2
|
|
#define NTFS_REPARSE_POINT_VERSION 2
|
|
#define NTFS_SPARSE_FILE_VERSION 2
|
|
|
|
#define NtfsVolumeVersionCheck(VCB,VERSION) ( \
|
|
((VCB)->MajorVersion >= VERSION) \
|
|
)
|
|
|
|
//
|
|
// Low level verification routines, implemented in VerfySup.c
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsPerformVerifyOperation (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsPerformDismountOnVcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN DoCompleteDismount,
|
|
OUT PVPB *NewVpbReturn OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsPingVolume (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN OUT PBOOLEAN OwnsVcb OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsVolumeCheckpointDpc (
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
);
|
|
|
|
VOID
|
|
NtfsCheckpointAllVolumes (
|
|
PVOID Parameter
|
|
);
|
|
|
|
VOID
|
|
NtfsUsnTimeOutDpc (
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
);
|
|
|
|
VOID
|
|
NtfsCheckUsnTimeOut (
|
|
PVOID Parameter
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsIoCallSelf (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN UCHAR MajorFunction
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsLogEvent (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PQUOTA_USER_DATA UserData OPTIONAL,
|
|
IN NTSTATUS LogCode,
|
|
IN NTSTATUS FinalStatus
|
|
);
|
|
|
|
VOID
|
|
NtfsMarkVolumeDirty (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsSetVolumeInfoFlagState (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN ULONG FlagsToSet,
|
|
IN BOOLEAN NewState,
|
|
IN BOOLEAN UpdateWithinTransaction
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsUpdateVolumeInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN UCHAR DiskMajorVersion,
|
|
IN UCHAR DiskMinorVersion
|
|
);
|
|
|
|
VOID
|
|
NtfsPostVcbIsCorrupt (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN NTSTATUS Status OPTIONAL,
|
|
IN PFILE_REFERENCE FileReference OPTIONAL,
|
|
IN PFCB Fcb OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtOfsCloseAttributeSafe (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsDeviceIoControlAsync (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG IoCtl,
|
|
IN OUT PVOID Buffer OPTIONAL,
|
|
IN ULONG BufferSize
|
|
);
|
|
|
|
|
|
//
|
|
// Work queue routines for posting and retrieving an Irp, implemented in
|
|
// workque.c
|
|
//
|
|
|
|
VOID
|
|
NtfsOplockComplete (
|
|
IN PVOID Context,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
NtfsPrePostIrp (
|
|
IN PVOID Context,
|
|
IN PIRP Irp OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsWriteOplockPrePostIrp (
|
|
IN PVOID Context,
|
|
IN PIRP Irp OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
NtfsPrePostIrpInternal (
|
|
IN PVOID Context,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN BOOLEAN PendIrp,
|
|
IN BOOLEAN SaveContext
|
|
);
|
|
|
|
VOID
|
|
NtfsAddToWorkque (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsPostRequest (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp OPTIONAL
|
|
);
|
|
|
|
|
|
//
|
|
// Miscellaneous support macros.
|
|
//
|
|
// ULONG_PTR
|
|
// WordAlign (
|
|
// IN ULONG_PTR Pointer
|
|
// );
|
|
//
|
|
// ULONG_PTR
|
|
// LongAlign (
|
|
// IN ULONG_PTR Pointer
|
|
// );
|
|
//
|
|
// ULONG_PTR
|
|
// QuadAlign (
|
|
// IN ULONG_PTR Pointer
|
|
// );
|
|
//
|
|
// UCHAR
|
|
// CopyUchar1 (
|
|
// IN PUCHAR Destination,
|
|
// IN PUCHAR Source
|
|
// );
|
|
//
|
|
// UCHAR
|
|
// CopyUchar2 (
|
|
// IN PUSHORT Destination,
|
|
// IN PUCHAR Source
|
|
// );
|
|
//
|
|
// UCHAR
|
|
// CopyUchar4 (
|
|
// IN PULONG Destination,
|
|
// IN PUCHAR Source
|
|
// );
|
|
//
|
|
// PVOID
|
|
// Add2Ptr (
|
|
// IN PVOID Pointer,
|
|
// IN ULONG Increment
|
|
// );
|
|
//
|
|
// ULONG
|
|
// PtrOffset (
|
|
// IN PVOID BasePtr,
|
|
// IN PVOID OffsetPtr
|
|
// );
|
|
//
|
|
|
|
#define WordAlignPtr(P) ( \
|
|
(PVOID)((((ULONG_PTR)(P)) + 1) & (-2)) \
|
|
)
|
|
|
|
#define LongAlignPtr(P) ( \
|
|
(PVOID)((((ULONG_PTR)(P)) + 3) & (-4)) \
|
|
)
|
|
|
|
#define QuadAlignPtr(P) ( \
|
|
(PVOID)((((ULONG_PTR)(P)) + 7) & (-8)) \
|
|
)
|
|
|
|
#define WordAlign(P) ( \
|
|
((((P)) + 1) & (-2)) \
|
|
)
|
|
|
|
#define LongAlign(P) ( \
|
|
((((P)) + 3) & (-4)) \
|
|
)
|
|
|
|
#define QuadAlign(P) ( \
|
|
((((P)) + 7) & (-8)) \
|
|
)
|
|
|
|
#define IsWordAligned(P) ((ULONG_PTR)(P) == WordAlign( (ULONG_PTR)(P) ))
|
|
|
|
#define IsLongAligned(P) ((ULONG_PTR)(P) == LongAlign( (ULONG_PTR)(P) ))
|
|
|
|
#define IsQuadAligned(P) ((ULONG_PTR)(P) == QuadAlign( (ULONG_PTR)(P) ))
|
|
|
|
//
|
|
// A note on structure alignment checking:
|
|
//
|
|
// In a perfect world, we would just use TYPE_ALIGNMENT straight out of the box
|
|
// to check the alignment requirements for a given structure.
|
|
//
|
|
// On 32-bit platforms including Alpha, alignment faults are handled by the
|
|
// OS. There are many places in the NTFS code where a structure requires
|
|
// quadword alignment (on Alpha) but only dword alignment is enforced. To
|
|
// change this on Alpha32 would introduce compatibility problems, so on 32-bit
|
|
// platforms we do not want to use an alignment value greater than 4.
|
|
//
|
|
// In other places, enforcing ULONG alignment is more restrictive than
|
|
// necessary. For example, a structure that contains nothing bigger than a
|
|
// USHORT can get by with 16-bit alignment. However, there is no reason to
|
|
// relax these alignment restrictions, so on all platforms we do not want to
|
|
// use an alignment value of less than 4.
|
|
//
|
|
// This means that NTFS_TYPE_ALIGNMENT always resolves to 4 on 32-bit platforms,
|
|
// and to at least four on 64-bit platforms.
|
|
//
|
|
|
|
#ifdef _WIN64
|
|
|
|
#define NTFS_TYPE_ALIGNMENT(T) \
|
|
((TYPE_ALIGNMENT( T ) < TYPE_ALIGNMENT(ULONG)) ? TYPE_ALIGNMENT( ULONG ) : TYPE_ALIGNMENT( T ))
|
|
|
|
#else
|
|
|
|
#define NTFS_TYPE_ALIGNMENT(T) TYPE_ALIGNMENT( ULONG )
|
|
|
|
#endif
|
|
|
|
//
|
|
// BlockAlign(): Aligns P on the next V boundary.
|
|
// BlockAlignTruncate(): Aligns P on the prev V boundary.
|
|
//
|
|
|
|
#define BlockAlign(P,V) ((ASSERT( V != 0)), (((P)) + (V-1) & (-(V))))
|
|
#define BlockAlignTruncate(P,V) ((P) & (-(V)))
|
|
|
|
//
|
|
// BlockOffset(): Calculates offset within V of P
|
|
//
|
|
|
|
#define BlockOffset(P,V) ((P) & (V-1))
|
|
|
|
//
|
|
// TypeAlign(): Aligns P according to the alignment requirements of type T
|
|
//
|
|
|
|
#define TypeAlign(P,T) BlockAlign( P, NTFS_TYPE_ALIGNMENT(T) )
|
|
|
|
//
|
|
// IsTypeAligned(): Determines whether P is aligned according to the
|
|
// requirements of type T
|
|
//
|
|
|
|
#define IsTypeAligned(P,T) \
|
|
((ULONG_PTR)(P) == TypeAlign( (ULONG_PTR)(P), T ))
|
|
|
|
//
|
|
// Conversions between bytes and clusters. Typically we will round up to the
|
|
// next cluster unless the macro specifies trucate.
|
|
//
|
|
|
|
#define ClusterAlign(V,P) ( \
|
|
((((ULONG)(P)) + (V)->ClusterMask) & (V)->InverseClusterMask) \
|
|
)
|
|
|
|
#define ClusterOffset(V,P) ( \
|
|
(((ULONG)(P)) & (V)->ClusterMask) \
|
|
)
|
|
|
|
#define ClustersFromBytes(V,P) ( \
|
|
(((ULONG)(P)) + (V)->ClusterMask) >> (V)->ClusterShift \
|
|
)
|
|
|
|
#define ClustersFromBytesTruncate(V,P) ( \
|
|
((ULONG)(P)) >> (V)->ClusterShift \
|
|
)
|
|
|
|
#define BytesFromClusters(V,P) ( \
|
|
((ULONG)(P)) << (V)->ClusterShift \
|
|
)
|
|
|
|
#define LlClustersFromBytes(V,L) ( \
|
|
Int64ShraMod32(((L) + (LONGLONG) (V)->ClusterMask), (CCHAR)(V)->ClusterShift) \
|
|
)
|
|
|
|
#define LlClustersFromBytesTruncate(V,L) ( \
|
|
Int64ShraMod32((L), (CCHAR)(V)->ClusterShift) \
|
|
)
|
|
|
|
#define LlBytesFromClusters(V,C) ( \
|
|
Int64ShllMod32((C), (CCHAR)(V)->ClusterShift) \
|
|
)
|
|
|
|
//
|
|
// Conversions between bytes and file records
|
|
//
|
|
|
|
#define BytesFromFileRecords(V,B) ( \
|
|
((ULONG)(B)) << (V)->MftShift \
|
|
)
|
|
|
|
#define FileRecordsFromBytes(V,F) ( \
|
|
((ULONG)(F)) >> (V)->MftShift \
|
|
)
|
|
|
|
#define LlBytesFromFileRecords(V,F) ( \
|
|
Int64ShllMod32((F), (CCHAR)(V)->MftShift) \
|
|
)
|
|
|
|
#define LlFileRecordsFromBytes(V,B) ( \
|
|
Int64ShraMod32((B), (CCHAR)(V)->MftShift) \
|
|
)
|
|
|
|
//
|
|
// Conversions between bytes and index blocks
|
|
//
|
|
|
|
#define BytesFromIndexBlocks(B,S) ( \
|
|
((ULONG)(B)) << (S) \
|
|
)
|
|
|
|
#define LlBytesFromIndexBlocks(B,S) ( \
|
|
Int64ShllMod32((B), (S)) \
|
|
)
|
|
|
|
//
|
|
// Conversions between bytes and log blocks (512 byte blocks)
|
|
//
|
|
|
|
#define BytesFromLogBlocks(B) ( \
|
|
((ULONG) (B)) << DEFAULT_INDEX_BLOCK_BYTE_SHIFT \
|
|
)
|
|
|
|
#define LogBlocksFromBytesTruncate(B) ( \
|
|
((ULONG) (B)) >> DEFAULT_INDEX_BLOCK_BYTE_SHIFT \
|
|
)
|
|
|
|
#define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I)))
|
|
|
|
#define PtrOffset(B,O) ((ULONG)((ULONG_PTR)(O) - (ULONG_PTR)(B)))
|
|
|
|
//
|
|
// The following support macros deal with dir notify support.
|
|
//
|
|
// ULONG
|
|
// NtfsBuildDirNotifyFilter (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN ULONG Flags
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsReportDirNotify (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb,
|
|
// IN PUNICODE_STRING FullFileName,
|
|
// IN USHORT TargetNameOffset,
|
|
// IN PUNICODE_STRING StreamName OPTIONAL,
|
|
// IN PUNICODE_STRING NormalizedParentName OPTIONAL,
|
|
// IN ULONG Filter,
|
|
// IN ULONG Action,
|
|
// IN PFCB ParentFcb OPTIONAL
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsUnsafeReportDirNotify (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PVCB Vcb,
|
|
// IN PUNICODE_STRING FullFileName,
|
|
// IN USHORT TargetNameOffset,
|
|
// IN PUNICODE_STRING StreamName OPTIONAL,
|
|
// IN PUNICODE_STRING NormalizedParentName OPTIONAL,
|
|
// IN ULONG Filter,
|
|
// IN ULONG Action,
|
|
// IN PFCB ParentFcb OPTIONAL
|
|
// );
|
|
//
|
|
|
|
#define NtfsBuildDirNotifyFilter(IC,F) ( \
|
|
FlagOn( (F), FCB_INFO_CHANGED_ALLOC_SIZE ) ? \
|
|
(FlagOn( (F), FCB_INFO_VALID_NOTIFY_FLAGS ) | FILE_NOTIFY_CHANGE_SIZE) : \
|
|
FlagOn( (F), FCB_INFO_VALID_NOTIFY_FLAGS ) \
|
|
)
|
|
|
|
#define NtfsReportDirNotify(IC,V,FN,O,SN,NPN,F,A,PF) { \
|
|
try { \
|
|
FsRtlNotifyFilterReportChange( (V)->NotifySync, \
|
|
&(V)->DirNotifyList, \
|
|
(PSTRING) (FN), \
|
|
(USHORT) (O), \
|
|
(PSTRING) (SN), \
|
|
(PSTRING) (NPN), \
|
|
F, \
|
|
A, \
|
|
PF, \
|
|
NULL ); \
|
|
} except (FsRtlIsNtstatusExpected( GetExceptionCode() ) ? \
|
|
EXCEPTION_EXECUTE_HANDLER : \
|
|
EXCEPTION_CONTINUE_SEARCH) { \
|
|
NOTHING; \
|
|
} \
|
|
}
|
|
|
|
#define NtfsUnsafeReportDirNotify(IC,V,FN,O,SN,NPN,F,A,PF) { \
|
|
FsRtlNotifyFilterReportChange( (V)->NotifySync, \
|
|
&(V)->DirNotifyList, \
|
|
(PSTRING) (FN), \
|
|
(USHORT) (O), \
|
|
(PSTRING) (SN), \
|
|
(PSTRING) (NPN), \
|
|
F, \
|
|
A, \
|
|
PF, \
|
|
NULL ); \
|
|
}
|
|
|
|
|
|
//
|
|
// The following types and macros are used to help unpack the packed and
|
|
// misaligned fields found in the Bios parameter block
|
|
//
|
|
|
|
typedef union _UCHAR1 {
|
|
UCHAR Uchar[1];
|
|
UCHAR ForceAlignment;
|
|
} UCHAR1, *PUCHAR1;
|
|
|
|
typedef union _UCHAR2 {
|
|
UCHAR Uchar[2];
|
|
USHORT ForceAlignment;
|
|
} UCHAR2, *PUCHAR2;
|
|
|
|
typedef union _UCHAR4 {
|
|
UCHAR Uchar[4];
|
|
ULONG ForceAlignment;
|
|
} UCHAR4, *PUCHAR4;
|
|
|
|
#define CopyUchar1(D,S) { \
|
|
*((UCHAR1 *)(D)) = *((UNALIGNED UCHAR1 *)(S)); \
|
|
}
|
|
|
|
#define CopyUchar2(D,S) { \
|
|
*((UCHAR2 *)(D)) = *((UNALIGNED UCHAR2 *)(S)); \
|
|
}
|
|
|
|
#define CopyUchar4(D,S) { \
|
|
*((UCHAR4 *)(D)) = *((UNALIGNED UCHAR4 *)(S)); \
|
|
}
|
|
|
|
//
|
|
// The following routines are used to set up and restore the top level
|
|
// irp field in the local thread. They are contained in ntfsdata.c
|
|
//
|
|
|
|
|
|
PTOP_LEVEL_CONTEXT
|
|
NtfsInitializeTopLevelIrp (
|
|
IN PTOP_LEVEL_CONTEXT TopLevelContext,
|
|
IN BOOLEAN ForceTopLevel,
|
|
IN BOOLEAN SetTopLevel
|
|
);
|
|
|
|
//
|
|
// BOOLEAN
|
|
// NtfsIsTopLevelRequest (
|
|
// IN PIRP_CONTEXT IrpContext
|
|
// );
|
|
//
|
|
// BOOLEAN
|
|
// NtfsIsTopLevelNtfs (
|
|
// IN PIRP_CONTEXT IrpContext
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsRestoreTopLevelIrp (
|
|
// );
|
|
//
|
|
// PTOP_LEVEL_CONTEXT
|
|
// NtfsGetTopLevelContext (
|
|
// );
|
|
//
|
|
// PSCB
|
|
// NtfsGetTopLevelHotFixScb (
|
|
// );
|
|
//
|
|
// VCN
|
|
// NtfsGetTopLevelHotFixVcn (
|
|
// );
|
|
//
|
|
// BOOLEAN
|
|
// NtfsIsTopLevelHotFixScb (
|
|
// IN PSCB Scb
|
|
// );
|
|
//
|
|
// VOID
|
|
// NtfsUpdateIrpContextWithTopLevel (
|
|
// IN PIRP_CONTEXT IrpContext,
|
|
// IN PTOP_LEVEL_CONTEXT TopLevelContext
|
|
// );
|
|
//
|
|
|
|
#define NtfsRestoreTopLevelIrp() { \
|
|
PTOP_LEVEL_CONTEXT TLC; \
|
|
TLC = (PTOP_LEVEL_CONTEXT) IoGetTopLevelIrp(); \
|
|
ASSERT( (TLC)->ThreadIrpContext != NULL ); \
|
|
(TLC)->Ntfs = 0; \
|
|
(TLC)->ThreadIrpContext = NULL; \
|
|
IoSetTopLevelIrp( (PIRP) (TLC)->SavedTopLevelIrp ); \
|
|
}
|
|
|
|
#define NtfsGetTopLevelContext() ( \
|
|
(PTOP_LEVEL_CONTEXT) IoGetTopLevelIrp() \
|
|
)
|
|
|
|
#define NtfsIsTopLevelRequest(IC) ( \
|
|
((IC) == (IC)->TopLevelIrpContext) && \
|
|
NtfsGetTopLevelContext()->TopLevelRequest \
|
|
)
|
|
|
|
#define NtfsIsTopLevelNtfs(IC) ( \
|
|
(IC) == (IC)->TopLevelIrpContext \
|
|
)
|
|
|
|
#define NtfsGetTopLevelHotFixScb() ( \
|
|
(NtfsGetTopLevelContext())->ScbBeingHotFixed \
|
|
)
|
|
|
|
#define NtfsGetTopLevelHotFixVcn() ( \
|
|
(NtfsGetTopLevelContext())->VboBeingHotFixed \
|
|
)
|
|
|
|
#define NtfsIsTopLevelHotFixScb(S) ( \
|
|
((BOOLEAN) (NtfsGetTopLevelHotFixScb() == (S))) \
|
|
)
|
|
|
|
#define NtfsUpdateIrpContextWithTopLevel(IC,TLC) { \
|
|
if ((TLC)->ThreadIrpContext == NULL) { \
|
|
(TLC)->Ntfs = 0x5346544e; \
|
|
(TLC)->ThreadIrpContext = (IC); \
|
|
SetFlag( (IC)->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ); \
|
|
IoSetTopLevelIrp( (PIRP) (TLC) ); \
|
|
} \
|
|
(IC)->TopLevelIrpContext = (TLC)->ThreadIrpContext; \
|
|
}
|
|
|
|
BOOLEAN
|
|
NtfsSetCancelRoutine (
|
|
IN PIRP Irp,
|
|
IN PDRIVER_CANCEL CancelRoutine,
|
|
IN ULONG_PTR IrpInformation,
|
|
IN ULONG Async
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsClearCancelRoutine (
|
|
IN PIRP Irp
|
|
);
|
|
|
|
#ifdef NTFS_CHECK_BITMAP
|
|
VOID
|
|
NtfsBadBitmapCopy (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN ULONG BadBit,
|
|
IN ULONG Length
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsCheckBitmap (
|
|
IN PVCB Vcb,
|
|
IN ULONG Lcn,
|
|
IN ULONG Count,
|
|
IN BOOLEAN Set
|
|
);
|
|
#endif
|
|
|
|
|
|
//
|
|
// The FSD Level dispatch routines. These routines are called by the
|
|
// I/O system via the dispatch table in the Driver Object.
|
|
//
|
|
// They each accept as input a pointer to a device object (actually most
|
|
// expect a volume device object, with the exception of the file system
|
|
// control function which can also take a file system device object), and
|
|
// a pointer to the IRP. They either perform the function at the FSD level
|
|
// or post the request to the FSP work queue for FSP level processing.
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
NtfsFsdDispatch ( // implemented in ntfsdata.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdDispatchWait ( // implemented in ntfsdata.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdCleanup ( // implemented in Cleanup.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdClose ( // implemented in Close.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdCreate ( // implemented in Create.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsDeviceIoControl ( // implemented in FsCtrl.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG IoCtl,
|
|
IN PVOID InputBuffer OPTIONAL,
|
|
IN ULONG InputBufferLength,
|
|
IN PVOID OutputBuffer OPTIONAL,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PULONG_PTR IosbInformation OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdDirectoryControl ( // implemented in DirCtrl.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdPnp ( // implemented in Pnp.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdFlushBuffers ( // implemented in Flush.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFlushUserStream ( // implemented in Flush.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PLONGLONG FileOffset OPTIONAL,
|
|
IN ULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFlushVolume ( // implemented in Flush.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN FlushCache,
|
|
IN BOOLEAN PurgeFromCache,
|
|
IN BOOLEAN ReleaseAllFiles,
|
|
IN BOOLEAN MarkFilesForDismount
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFlushLsnStreams ( // implemented in Flush.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN ForceRemove,
|
|
IN BOOLEAN Partial
|
|
);
|
|
|
|
VOID
|
|
NtfsFlushAndPurgeFcb ( // implemented in Flush.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
VOID
|
|
NtfsFlushAndPurgeScb ( // implemented in Flush.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN PSCB ParentScb OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdFileSystemControl ( // implemented in FsCtrl.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdLockControl ( // implemented in LockCtrl.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdRead ( // implemented in Read.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdSetInformation ( // implemented in FileInfo.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdShutdown ( // implemented in Shutdown.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdQueryVolumeInformation ( // implemented in VolInfo.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdSetVolumeInformation ( // implemented in VolInfo.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsdWrite ( // implemented in Write.c
|
|
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
//
|
|
// The following macro is used to determine if an FSD thread can block
|
|
// for I/O or wait for a resource. It returns TRUE if the thread can
|
|
// block and FALSE otherwise. This attribute can then be used to call
|
|
// the FSD & FSP common work routine with the proper wait value.
|
|
//
|
|
//
|
|
// BOOLEAN
|
|
// CanFsdWait (
|
|
// IN PIRP Irp
|
|
// );
|
|
//
|
|
|
|
#define CanFsdWait(I) IoIsOperationSynchronous(I)
|
|
|
|
|
|
//
|
|
// The FSP level dispatch/main routine. This is the routine that takes
|
|
// IRP's off of the work queue and calls the appropriate FSP level
|
|
// work routine.
|
|
//
|
|
|
|
VOID
|
|
NtfsFspDispatch ( // implemented in FspDisp.c
|
|
IN PVOID Context
|
|
);
|
|
|
|
//
|
|
// The following routines are the FSP work routines that are called
|
|
// by the preceding NtfsFspDispath routine. Each takes as input a pointer
|
|
// to the IRP, perform the function, and return a pointer to the volume
|
|
// device object that they just finished servicing (if any). The return
|
|
// pointer is then used by the main Fsp dispatch routine to check for
|
|
// additional IRPs in the volume's overflow queue.
|
|
//
|
|
// Each of the following routines is also responsible for completing the IRP.
|
|
// We moved this responsibility from the main loop to the individual routines
|
|
// to allow them the ability to complete the IRP and continue post processing
|
|
// actions.
|
|
//
|
|
|
|
NTSTATUS
|
|
NtfsCommonCleanup ( // implemented in Cleanup.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
LONG
|
|
NtfsCleanupExceptionFilter ( // implemented in Cleanup.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PEXCEPTION_POINTERS ExceptionPointer,
|
|
OUT PNTSTATUS Status
|
|
);
|
|
|
|
VOID
|
|
NtfsFspClose ( // implemented in Close.c
|
|
IN PVCB ThisVcb OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsAddScbToFspClose ( // implemented in Close.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSCB Scb,
|
|
IN BOOLEAN DelayClose
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsNetworkOpenCreate ( // implemented in Create.c
|
|
IN PIRP Irp,
|
|
OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
|
|
IN PDEVICE_OBJECT VolumeDeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonCreate ( // implemented in Create.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PCREATE_CONTEXT CreateContext
|
|
);
|
|
|
|
VOID
|
|
NtfsInitializeFcbAndStdInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB ThisFcb,
|
|
IN BOOLEAN Directory,
|
|
IN BOOLEAN ViewIndex,
|
|
IN BOOLEAN Compressed,
|
|
IN ULONG FileAttributes,
|
|
IN PNTFS_TUNNELED_DATA SetTunnelData OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonVolumeOpen ( // implemented in Create.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonDeviceControl ( // implemented in DevCtrl.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonDirectoryControl ( // implemented in DirCtrl.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
NtfsReportViewIndexNotify ( // implemented in DirCtrl.c
|
|
IN PVCB Vcb,
|
|
IN PFCB Fcb,
|
|
IN ULONG FilterMatch,
|
|
IN ULONG Action,
|
|
IN PVOID ChangeInfoBuffer,
|
|
IN USHORT ChangeInfoBufferLength
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonQueryEa ( // implemented in Ea.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonSetEa ( // implemented in Ea.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonQueryInformation ( // implemented in FileInfo.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonSetInformation ( // implemented in FileInfo.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS // implemented in FsCtrl.c
|
|
NtfsGetTunneledData (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN OUT PNTFS_TUNNELED_DATA TunneledData
|
|
);
|
|
|
|
NTSTATUS // implemented in FsCtrl.c
|
|
NtfsSetTunneledData (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PNTFS_TUNNELED_DATA TunneledData
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonQueryQuota ( // implemented in Quota.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonSetQuota ( // implemented in Quota.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonFlushBuffers ( // implemented in Flush.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonFileSystemControl ( // implemented in FsCtrl.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonLockControl ( // implemented in LockCtrl.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonRead ( // implemented in Read.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN BOOLEAN AcquireScb
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonQuerySecurityInfo ( // implemented in SeInfo.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonSetSecurityInfo ( // implemented in SeInfo.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsQueryViewIndex ( // implemented in ViewSup.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PVCB Vcb,
|
|
IN PSCB Scb,
|
|
IN PCCB Ccb
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonQueryVolumeInfo ( // implemented in VolInfo.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonSetVolumeInfo ( // implemented in VolInfo.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsCommonWrite ( // implemented in Write.c
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
|
|
//
|
|
// The following procedure is used by the FSP and FSD routines to complete
|
|
// an IRP. Either the Irp or IrpContext may be NULL depending on whether
|
|
// this is being done for a user or for a FS service.
|
|
//
|
|
// This would typically be done in order to pass a "naked" IrpContext off to
|
|
// the Fsp for post processing, such as read ahead.
|
|
//
|
|
|
|
VOID
|
|
NtfsCompleteRequest (
|
|
IN OUT PIRP_CONTEXT IrpContext OPTIONAL,
|
|
IN OUT PIRP Irp OPTIONAL,
|
|
IN NTSTATUS Status
|
|
);
|
|
|
|
//
|
|
// Here are the callbacks used by the I/O system for checking for fast I/O or
|
|
// doing a fast query info call, or doing fast lock calls.
|
|
//
|
|
|
|
BOOLEAN
|
|
NtfsFastIoCheckIfPossible (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Wait,
|
|
IN ULONG LockKey,
|
|
IN BOOLEAN CheckForReadOperation,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFastQueryBasicInfo (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN BOOLEAN Wait,
|
|
IN OUT PFILE_BASIC_INFORMATION Buffer,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFastQueryStdInfo (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN BOOLEAN Wait,
|
|
IN OUT PFILE_STANDARD_INFORMATION Buffer,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFastLock (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN PLARGE_INTEGER Length,
|
|
PEPROCESS ProcessId,
|
|
ULONG Key,
|
|
BOOLEAN FailImmediately,
|
|
BOOLEAN ExclusiveLock,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFastUnlockSingle (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN PLARGE_INTEGER Length,
|
|
PEPROCESS ProcessId,
|
|
ULONG Key,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFastUnlockAll (
|
|
IN PFILE_OBJECT FileObject,
|
|
PEPROCESS ProcessId,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFastUnlockAllByKey (
|
|
IN PFILE_OBJECT FileObject,
|
|
PVOID ProcessId,
|
|
ULONG Key,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
NtfsFastQueryNetworkOpenInfo (
|
|
IN struct _FILE_OBJECT *FileObject,
|
|
IN BOOLEAN Wait,
|
|
OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer,
|
|
OUT struct _IO_STATUS_BLOCK *IoStatus,
|
|
IN struct _DEVICE_OBJECT *DeviceObject
|
|
);
|
|
|
|
VOID
|
|
NtfsFastIoQueryCompressionInfo (
|
|
IN PFILE_OBJECT FileObject,
|
|
OUT PFILE_COMPRESSION_INFORMATION Buffer,
|
|
OUT PIO_STATUS_BLOCK IoStatus
|
|
);
|
|
|
|
VOID
|
|
NtfsFastIoQueryCompressedSize (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
OUT PULONG CompressedSize
|
|
);
|
|
|
|
//
|
|
// The following macro is used by the dispatch routines to determine if
|
|
// an operation is to be done with or without WriteThrough.
|
|
//
|
|
// BOOLEAN
|
|
// IsFileWriteThrough (
|
|
// IN PFILE_OBJECT FileObject,
|
|
// IN PVCB Vcb
|
|
// );
|
|
//
|
|
|
|
#define IsFileWriteThrough(FO,V) ( \
|
|
FlagOn((FO)->Flags, FO_WRITE_THROUGH) \
|
|
)
|
|
|
|
//
|
|
// The following macro is used to set the is fast i/o possible field in
|
|
// the common part of the non paged fcb
|
|
//
|
|
// NotPossible - Volume not mounted
|
|
// - Oplock state prevents it
|
|
//
|
|
// Possible - Not compressed or sparse
|
|
// - No file locks
|
|
// - Not a read only volume
|
|
// - No Usn journal for this volume
|
|
//
|
|
// Questionable - All other cases
|
|
//
|
|
//
|
|
// BOOLEAN
|
|
// NtfsIsFastIoPossible (
|
|
// IN PSCB Scb
|
|
// );
|
|
//
|
|
|
|
#define NtfsIsFastIoPossible(S) (BOOLEAN) ( \
|
|
(!FlagOn((S)->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED) || \
|
|
!FsRtlOplockIsFastIoPossible( &(S)->ScbType.Data.Oplock )) ? \
|
|
\
|
|
FastIoIsNotPossible : \
|
|
\
|
|
((((S)->CompressionUnit == 0) && \
|
|
(((S)->ScbType.Data.FileLock == NULL) || \
|
|
!FsRtlAreThereCurrentFileLocks( (S)->ScbType.Data.FileLock )) && \
|
|
!NtfsIsVolumeReadOnly( (S)->Vcb ) && \
|
|
((S)->Vcb->UsnJournal == NULL)) ? \
|
|
\
|
|
FastIoIsPossible : \
|
|
\
|
|
FastIoIsQuestionable) \
|
|
)
|
|
|
|
//
|
|
// The following macro is used to detemine if the file object is opened
|
|
// for read only access (i.e., it is not also opened for write access or
|
|
// delete access).
|
|
//
|
|
// BOOLEAN
|
|
// IsFileObjectReadOnly (
|
|
// IN PFILE_OBJECT FileObject
|
|
// );
|
|
//
|
|
|
|
#define IsFileObjectReadOnly(FO) (!((FO)->WriteAccess | (FO)->DeleteAccess))
|
|
|
|
|
|
//
|
|
// The following macros are used to establish the semantics needed
|
|
// to do a return from within a try-finally clause. As a rule every
|
|
// try clause must end with a label call try_exit. For example,
|
|
//
|
|
// try {
|
|
// :
|
|
// :
|
|
//
|
|
// try_exit: NOTHING;
|
|
// } finally {
|
|
//
|
|
// :
|
|
// :
|
|
// }
|
|
//
|
|
// Every return statement executed inside of a try clause should use the
|
|
// try_return macro. If the compiler fully supports the try-finally construct
|
|
// then the macro should be
|
|
//
|
|
// #define try_return(S) { return(S); }
|
|
//
|
|
// If the compiler does not support the try-finally construct then the macro
|
|
// should be
|
|
//
|
|
// #define try_return(S) { S; goto try_exit; }
|
|
//
|
|
|
|
#define try_return(S) { S; goto try_exit; }
|
|
|
|
|
|
//
|
|
// Simple initialization for a name pair
|
|
//
|
|
// VOID
|
|
// NtfsInitializeNamePair(PNAME_PAIR PNp);
|
|
//
|
|
|
|
#define NtfsInitializeNamePair(PNp) { \
|
|
(PNp)->Short.Buffer = (PNp)->ShortBuffer; \
|
|
(PNp)->Long.Buffer = (PNp)->LongBuffer; \
|
|
(PNp)->Short.Length = 0; \
|
|
(PNp)->Long.Length = 0; \
|
|
(PNp)->Short.MaximumLength = sizeof((PNp)->ShortBuffer); \
|
|
(PNp)->Long.MaximumLength = sizeof((PNp)->LongBuffer); \
|
|
}
|
|
|
|
//
|
|
// Copy a length of WCHARs into a side of a name pair. Only copy the first name
|
|
// that fits to avoid useless work if more than three links are encountered (per
|
|
// BrianAn), very rare case. We use the filename flags to figure out what kind of
|
|
// name we have.
|
|
//
|
|
// VOID
|
|
// NtfsCopyNameToNamePair(
|
|
// PNAME_PAIR PNp,
|
|
// WCHAR Source,
|
|
// ULONG SourceLen,
|
|
// UCHAR NameFlags);
|
|
//
|
|
|
|
#define NtfsCopyNameToNamePair(PNp, Source, SourceLen, NameFlags) { \
|
|
if (!FlagOn((NameFlags), FILE_NAME_DOS)) { \
|
|
if ((PNp)->Long.Length == 0) { \
|
|
if ((PNp)->Long.MaximumLength < ((SourceLen)*sizeof(WCHAR))) { \
|
|
if ((PNp)->Long.Buffer != (PNp)->LongBuffer) { \
|
|
NtfsFreePool((PNp)->Long.Buffer); \
|
|
(PNp)->Long.Buffer = (PNp)->LongBuffer; \
|
|
(PNp)->Long.MaximumLength = sizeof((PNp)->LongBuffer); \
|
|
} \
|
|
(PNp)->Long.Buffer = NtfsAllocatePool(PagedPool,(SourceLen)*sizeof(WCHAR)); \
|
|
(PNp)->Long.MaximumLength = (SourceLen)*sizeof(WCHAR); \
|
|
} \
|
|
RtlCopyMemory((PNp)->Long.Buffer, (Source), (SourceLen)*sizeof(WCHAR)); \
|
|
(PNp)->Long.Length = (SourceLen)*sizeof(WCHAR); \
|
|
} \
|
|
} else { \
|
|
ASSERT((PNp)->Short.Buffer == (PNp)->ShortBuffer); \
|
|
if ((PNp)->Short.Length == 0) { \
|
|
RtlCopyMemory((PNp)->Short.Buffer, (Source), (SourceLen)*sizeof(WCHAR)); \
|
|
(PNp)->Short.Length = (SourceLen)*sizeof(WCHAR); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// Set up a previously used name pair for reuse.
|
|
//
|
|
// VOID
|
|
// NtfsResetNamePair(PNAME_PAIR PNp);
|
|
//
|
|
|
|
#define NtfsResetNamePair(PNp) { \
|
|
if ((PNp)->Long.Buffer != (PNp)->LongBuffer) { \
|
|
NtfsFreePool((PNp)->Long.Buffer); \
|
|
} \
|
|
NtfsInitializeNamePair(PNp); \
|
|
}
|
|
|
|
//
|
|
// Cairo support stuff.
|
|
//
|
|
|
|
typedef NTSTATUS
|
|
(*FILE_RECORD_WALK) (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN OUT PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsIterateMft (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN OUT PFILE_REFERENCE FileReference,
|
|
IN FILE_RECORD_WALK FileRecordFunction,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
NtfsPostSpecial (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN POST_SPECIAL_CALLOUT PostSpecialCallout,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
NtfsSpecialDispatch (
|
|
PVOID Context
|
|
);
|
|
|
|
VOID
|
|
NtfsLoadAddOns (
|
|
IN struct _DRIVER_OBJECT *DriverObject,
|
|
IN PVOID Context,
|
|
IN ULONG Count
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsTryOpenFcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
OUT PFCB *CurrentFcb,
|
|
IN FILE_REFERENCE FileReference
|
|
);
|
|
|
|
//
|
|
// The following define controls whether quota operations are done
|
|
// on this FCB.
|
|
//
|
|
|
|
#define NtfsPerformQuotaOperation(FCB) ((FCB)->QuotaControl != NULL)
|
|
|
|
VOID
|
|
NtfsAcquireQuotaControl (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PQUOTA_CONTROL_BLOCK QuotaControl
|
|
);
|
|
|
|
VOID
|
|
NtfsCalculateQuotaAdjustment (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
OUT PLONGLONG Delta
|
|
);
|
|
|
|
VOID
|
|
NtfsDereferenceQuotaControlBlock (
|
|
IN PVCB Vcb,
|
|
IN PQUOTA_CONTROL_BLOCK *QuotaControl
|
|
);
|
|
|
|
VOID
|
|
NtfsFixupQuota (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsQuotaQueryInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN ULONG StartingId,
|
|
IN BOOLEAN ReturnSingleEntry,
|
|
IN PFILE_QUOTA_INFORMATION *FileQuotaInfo,
|
|
IN OUT PULONG Length,
|
|
IN OUT PCCB Ccb OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsFsQuotaSetInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFILE_QUOTA_INFORMATION FileQuotaInfo,
|
|
IN ULONG Length
|
|
);
|
|
|
|
VOID
|
|
NtfsGetRemainingQuota (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN ULONG OwnerId,
|
|
OUT PULONGLONG RemainingQuota,
|
|
OUT PULONGLONG TotalQuota,
|
|
IN OUT PQUICK_INDEX_HINT QuickIndexHint OPTIONAL
|
|
);
|
|
|
|
ULONG
|
|
NtfsGetCallersUserId (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
ULONG
|
|
NtfsGetOwnerId (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PSID Sid,
|
|
IN BOOLEAN CreateNew,
|
|
IN PFILE_QUOTA_INFORMATION FileQuotaInfo OPTIONAL
|
|
);
|
|
|
|
PQUOTA_CONTROL_BLOCK
|
|
NtfsInitializeQuotaControlBlock (
|
|
IN PVCB Vcb,
|
|
IN ULONG OwnerId
|
|
);
|
|
|
|
VOID
|
|
NtfsInitializeQuotaIndex (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsMarkQuotaCorrupt (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
VOID
|
|
NtfsRepairQuotaIndex (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
NtfsMoveQuotaOwner (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSECURITY_DESCRIPTOR Security
|
|
);
|
|
|
|
|
|
VOID
|
|
NtfsPostRepairQuotaIndex (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
NTSTATUS
|
|
NtfsQueryQuotaUserSidList (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFILE_GET_QUOTA_INFORMATION SidList,
|
|
OUT PFILE_QUOTA_INFORMATION QuotaBuffer,
|
|
IN OUT PULONG BufferLength,
|
|
IN BOOLEAN ReturnSingleEntry
|
|
);
|
|
|
|
VOID
|
|
NtfsReleaseQuotaControl (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PQUOTA_CONTROL_BLOCK QuotaControl
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateFileQuota (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PLONGLONG Delta,
|
|
IN LOGICAL LogIt,
|
|
IN LOGICAL CheckQuota
|
|
);
|
|
|
|
VOID
|
|
NtfsUpdateQuotaDefaults (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN PFILE_FS_CONTROL_INFORMATION FileQuotaInfo
|
|
);
|
|
|
|
INLINE
|
|
VOID
|
|
NtfsConditionallyFixupQuota (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb
|
|
)
|
|
{
|
|
if (FlagOn( Fcb->Vcb->QuotaFlags, QUOTA_FLAG_TRACKING_ENABLED )) {
|
|
NtfsFixupQuota ( IrpContext, Fcb );
|
|
}
|
|
}
|
|
|
|
INLINE
|
|
VOID
|
|
NtfsConditionallyUpdateQuota (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PLONGLONG Delta,
|
|
IN LOGICAL LogIt,
|
|
IN LOGICAL CheckQuota
|
|
)
|
|
{
|
|
if (NtfsPerformQuotaOperation( Fcb ) &&
|
|
!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_QUOTA_DISABLE )) {
|
|
NtfsUpdateFileQuota( IrpContext, Fcb, Delta, LogIt, CheckQuota );
|
|
}
|
|
}
|
|
|
|
extern BOOLEAN NtfsAllowFixups;
|
|
|
|
INLINE
|
|
VOID
|
|
NtfsReleaseQuotaIndex (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN Acquired
|
|
)
|
|
{
|
|
if (Acquired) {
|
|
NtfsReleaseScb( IrpContext, Vcb->QuotaTableScb );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Define the quota charge for resident streams.
|
|
//
|
|
|
|
#define NtfsResidentStreamQuota( Vcb ) ((LONG) Vcb->BytesPerFileRecordSegment)
|
|
|
|
|
|
//
|
|
// The following macro tests to see if it is ok for an internal routine to
|
|
// write to the volume.
|
|
//
|
|
|
|
#define NtfsIsVcbAvailable( Vcb ) (FlagOn( Vcb->VcbState, \
|
|
VCB_STATE_VOLUME_MOUNTED | \
|
|
VCB_STATE_FLAG_SHUTDOWN | \
|
|
VCB_STATE_PERFORMED_DISMOUNT | \
|
|
VCB_STATE_LOCKED) == VCB_STATE_VOLUME_MOUNTED)
|
|
|
|
//
|
|
// Test to see if the volume is mounted read only.
|
|
//
|
|
|
|
#define NtfsIsVolumeReadOnly( Vcb ) (FlagOn( (Vcb)->VcbState, VCB_STATE_MOUNT_READ_ONLY ))
|
|
|
|
//
|
|
// Processing required so reg. exception filter works if another one is being used
|
|
// to handle an exception that could be raise via NtfsRaiseStatus. If its always
|
|
// rethrown this is not necc.
|
|
//
|
|
|
|
#define NtfsMinimumExceptionProcessing(I) { \
|
|
if((I) != NULL) { \
|
|
ClearFlag( (I)->Flags, IRP_CONTEXT_FLAG_RAISED_STATUS ); \
|
|
} \
|
|
}
|
|
|
|
#ifdef NTFSDBG
|
|
|
|
BOOLEAN
|
|
NtfsChangeResourceOrderState(
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN NTFS_RESOURCE_NAME NewResource,
|
|
IN BOOLEAN Release,
|
|
IN ULONG UnsafeTransition
|
|
);
|
|
|
|
NTFS_RESOURCE_NAME
|
|
NtfsIdentifyFcb (
|
|
IN PVCB Vcb,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Size of a normalized name which is long enough to be freed at cleanup
|
|
//
|
|
|
|
#define LONGNAME_THRESHOLD 0x200
|
|
|
|
VOID
|
|
NtfsTrimNormalizedNames (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFCB Fcb,
|
|
IN PSCB ParentScb
|
|
);
|
|
|
|
#define NtfsSnapshotFileSizesTest( I, S ) (FlagOn( (S)->ScbState, SCB_STATE_MODIFIED_NO_WRITE | SCB_STATE_CONVERT_UNDERWAY ) || \
|
|
((S) == (I)->CleanupStructure) || \
|
|
((S)->Fcb == (I)->CleanupStructure))
|
|
|
|
//
|
|
// Reservation needed = AllocationSize
|
|
// largest transfer size - this is because in a single transfer we cannot reuse clusters we freed from the totalallocated piece of the calculation
|
|
// metadata charge for new clusters
|
|
// minus the already allocated space
|
|
//
|
|
|
|
|
|
//
|
|
// One problem with the reservation strategy, is that we cannot precisely reserve
|
|
// for metadata. If we reserve too much, we will return premature disk full, if
|
|
// we reserve too little, the Lazy Writer can get an error. As we add compression
|
|
// units to a file, large files will eventually require additional File Records.
|
|
// If each compression unit required 0x20 bytes of run information (fairly pessimistic)
|
|
// then a 0x400 size file record would fill up with less than 0x20 runs requiring
|
|
// (worst case) two additional clusters for another file record. So each 0x20
|
|
// compression units require 0x200 reserved clusters, and a separate 2 cluster
|
|
// file record. 0x200/2 = 0x100. So the calculations below tack a 1/0x100 (about
|
|
// .4% "surcharge" on the amount reserved both in the Scb and the Vcb, to solve
|
|
// the Lazy Writer popups like the ones Alan Morris gets in the print lab.
|
|
//
|
|
|
|
#define NtfsCalculateNeededReservedSpace( S ) \
|
|
((S)->Header.AllocationSize.QuadPart + \
|
|
MM_MAXIMUM_DISK_IO_SIZE + \
|
|
(S)->CompressionUnit - \
|
|
(FlagOn( (S)->Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS ) ? \
|
|
(S)->Header.AllocationSize.QuadPart : \
|
|
(S)->TotalAllocated) + \
|
|
(Int64ShraMod32( (S)->ScbType.Data.TotalReserved, 8 )))
|
|
|
|
|
|
PDEALLOCATED_CLUSTERS
|
|
NtfsGetDeallocatedClusters (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PVCB Vcb
|
|
);
|
|
|
|
//
|
|
// Dynamically allocate stack space for local variables.
|
|
//
|
|
|
|
#define NtfsAllocateFromStack(S) _alloca(S)
|
|
|
|
//
|
|
// Common Create Flag definitions
|
|
//
|
|
|
|
#define CREATE_FLAG_DOS_ONLY_COMPONENT (0x00000001)
|
|
#define CREATE_FLAG_CREATE_FILE_CASE (0x00000002)
|
|
#define CREATE_FLAG_DELETE_ON_CLOSE (0x00000004)
|
|
#define CREATE_FLAG_TRAILING_BACKSLASH (0x00000008)
|
|
#define CREATE_FLAG_TRAVERSE_CHECK (0x00000010)
|
|
#define CREATE_FLAG_IGNORE_CASE (0x00000020)
|
|
#define CREATE_FLAG_OPEN_BY_ID (0x00000040)
|
|
#define CREATE_FLAG_ACQUIRED_OBJECT_ID_INDEX (0x00000080)
|
|
#define CREATE_FLAG_BACKOUT_FAILED_OPENS (0x00000100)
|
|
#define CREATE_FLAG_INSPECT_NAME_FOR_REPARSE (0x00000200)
|
|
#define CREATE_FLAG_SHARED_PARENT_FCB (0x00000400)
|
|
#define CREATE_FLAG_ACQUIRED_VCB (0x00000800)
|
|
|
|
#define CREATE_FLAG_FIRST_PASS (0x00002000)
|
|
#define CREATE_FLAG_FOUND_ENTRY (0x00004000)
|
|
#define CREATE_FLAG_EXPLICIT_ATTRIBUTE_CODE (0x00008000)
|
|
|
|
//
|
|
// The following macro gives the effective mode to do security related checks based on the irp
|
|
// If the irp is for a create request: The force_check flag only is defined for creates
|
|
//
|
|
//
|
|
// KPROCESSOR_MODE
|
|
// NtfsEffectiveMode (
|
|
// IN PIRP Irp,
|
|
// IN PIO_STACK_LOCATION IrpSp
|
|
// );
|
|
//
|
|
|
|
#define NtfsEffectiveMode( I, IS ) (ASSERT( (IS)->MajorFunction == IRP_MJ_CREATE), (FlagOn( (IS)->Flags, SL_FORCE_ACCESS_CHECK )) ? UserMode : (I)->RequestorMode )
|
|
|
|
#endif // _NTFSPROC_
|