ReactOS 0.4.16-dev-311-g9382aa2
ntfs.h File Reference
#include <ntifs.h>
#include <pseh/pseh2.h>
#include <section_attribs.h>
#include <pshpack1.h>
#include <poppack.h>
Include dependency graph for ntfs.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  _BIOS_PARAMETERS_BLOCK
 
struct  _EXTENDED_BIOS_PARAMETERS_BLOCK
 
struct  _BOOT_SECTOR
 
struct  _NTFS_INFO
 
struct  NTFSIDENTIFIER
 
struct  DEVICE_EXTENSION
 
struct  NTFS_CCB
 
struct  NTFS_GLOBAL_DATA
 
struct  NTFS_RECORD_HEADER
 
struct  _FILE_RECORD_HEADER
 
struct  NTFS_ATTR_RECORD
 
struct  NTFS_ATTRIBUTE_LIST_ITEM
 
struct  STANDARD_INFORMATION
 
struct  ATTRIBUTE_LIST
 
struct  FILENAME_ATTRIBUTE
 
struct  INDEX_HEADER_ATTRIBUTE
 
struct  INDEX_ROOT_ATTRIBUTE
 
struct  INDEX_BUFFER
 
struct  INDEX_ENTRY_ATTRIBUTE
 
struct  _B_TREE_KEY
 
struct  _B_TREE_FILENAME_NODE
 
struct  B_TREE
 
struct  VOLINFO_ATTRIBUTE
 
struct  REPARSE_POINT_ATTRIBUTE
 
struct  NTFS_IRP_CONTEXT
 
struct  _NTFS_ATTR_CONTEXT
 
struct  _FCB
 
struct  _FIND_ATTR_CONTXT
 
struct  FIXUP_ARRAY
 

Macros

#define CACHEPAGESIZE(pDeviceExt)
 
#define TAG_NTFS   '0ftN'
 
#define TAG_CCB   'CftN'
 
#define TAG_FCB   'FftN'
 
#define TAG_IRP_CTXT   'iftN'
 
#define TAG_ATT_CTXT   'aftN'
 
#define TAG_FILE_REC   'rftN'
 
#define ROUND_UP(N, S)   ((((N) + (S) - 1) / (S)) * (S))
 
#define ROUND_DOWN(N, S)   ((N) - ((N) % (S)))
 
#define DEVICE_NAME   L"\\Ntfs"
 
#define NTFS_TYPE_CCB   '20SF'
 
#define NTFS_TYPE_FCB   '30SF'
 
#define NTFS_TYPE_VCB   '50SF'
 
#define NTFS_TYPE_IRP_CONTEXT   '60SF'
 
#define NTFS_TYPE_GLOBAL_DATA   '70SF'
 
#define VCB_VOLUME_LOCKED   0x0001
 
#define FILE_RECORD_END   0x11477982
 
#define NTFS_FILE_MFT   0
 
#define NTFS_FILE_MFTMIRR   1
 
#define NTFS_FILE_LOGFILE   2
 
#define NTFS_FILE_VOLUME   3
 
#define NTFS_FILE_ATTRDEF   4
 
#define NTFS_FILE_ROOT   5
 
#define NTFS_FILE_BITMAP   6
 
#define NTFS_FILE_BOOT   7
 
#define NTFS_FILE_BADCLUS   8
 
#define NTFS_FILE_QUOTA   9
 
#define NTFS_FILE_UPCASE   10
 
#define NTFS_FILE_EXTEND   11
 
#define NTFS_FILE_FIRST_USER_FILE   16
 
#define NTFS_MFT_MASK   0x0000FFFFFFFFFFFFULL
 
#define COLLATION_BINARY   0x00
 
#define COLLATION_FILE_NAME   0x01
 
#define COLLATION_UNICODE_STRING   0x02
 
#define COLLATION_NTOFS_ULONG   0x10
 
#define COLLATION_NTOFS_SID   0x11
 
#define COLLATION_NTOFS_SECURITY_HASH   0x12
 
#define COLLATION_NTOFS_ULONGS   0x13
 
#define INDEX_ROOT_SMALL   0x0
 
#define INDEX_ROOT_LARGE   0x1
 
#define INDEX_NODE_SMALL   0x0
 
#define INDEX_NODE_LARGE   0x1
 
#define NTFS_INDEX_ENTRY_NODE   1
 
#define NTFS_INDEX_ENTRY_END   2
 
#define NTFS_FILE_NAME_POSIX   0
 
#define NTFS_FILE_NAME_WIN32   1
 
#define NTFS_FILE_NAME_DOS   2
 
#define NTFS_FILE_NAME_WIN32_AND_DOS   3
 
#define NTFS_FILE_TYPE_READ_ONLY   0x1
 
#define NTFS_FILE_TYPE_HIDDEN   0x2
 
#define NTFS_FILE_TYPE_SYSTEM   0x4
 
#define NTFS_FILE_TYPE_ARCHIVE   0x20
 
#define NTFS_FILE_TYPE_TEMPORARY   0x100
 
#define NTFS_FILE_TYPE_SPARSE   0x200
 
#define NTFS_FILE_TYPE_REPARSE   0x400
 
#define NTFS_FILE_TYPE_COMPRESSED   0x800
 
#define NTFS_FILE_TYPE_OFFLINE   0x1000
 
#define NTFS_FILE_TYPE_ENCRYPTED   0x4000
 
#define NTFS_FILE_TYPE_DIRECTORY   0x10000000
 
#define RA_INDEXED   0x01
 
#define NRH_FILE_TYPE   0x454C4946 /* 'FILE' */
 
#define NRH_INDX_TYPE   0x58444E49 /* 'INDX' */
 
#define FRH_IN_USE   0x0001 /* Record is in use */
 
#define FRH_DIRECTORY   0x0002 /* Record is a directory */
 
#define FRH_UNKNOWN1   0x0004 /* Don't know */
 
#define FRH_UNKNOWN2   0x0008 /* Don't know */
 
#define ATTR_RECORD_ALIGNMENT   8
 
#define DATA_RUN_ALIGNMENT   4
 
#define VALUE_OFFSET_ALIGNMENT   4
 
#define IRPCONTEXT_CANWAIT   0x1
 
#define IRPCONTEXT_COMPLETE   0x2
 
#define IRPCONTEXT_QUEUE   0x4
 
#define FCB_CACHE_INITIALIZED   0x0001
 
#define FCB_IS_VOLUME_STREAM   0x0002
 
#define FCB_IS_VOLUME   0x0004
 
#define MAX_PATH   260
 

Typedefs

typedef struct _BIOS_PARAMETERS_BLOCK BIOS_PARAMETERS_BLOCK
 
typedef struct _BIOS_PARAMETERS_BLOCKPBIOS_PARAMETERS_BLOCK
 
typedef struct _EXTENDED_BIOS_PARAMETERS_BLOCK EXTENDED_BIOS_PARAMETERS_BLOCK
 
typedef struct _EXTENDED_BIOS_PARAMETERS_BLOCKPEXTENDED_BIOS_PARAMETERS_BLOCK
 
typedef struct _BOOT_SECTOR BOOT_SECTOR
 
typedef struct _BOOT_SECTORPBOOT_SECTOR
 
typedef struct _NTFS_INFO NTFS_INFO
 
typedef struct _NTFS_INFOPNTFS_INFO
 
typedef struct NTFSIDENTIFIERPNTFSIDENTIFIER
 
typedef struct DEVICE_EXTENSIONPDEVICE_EXTENSION
 
typedef struct DEVICE_EXTENSION NTFS_VCB
 
typedef struct DEVICE_EXTENSIONPNTFS_VCB
 
typedef struct NTFS_CCBPNTFS_CCB
 
typedef struct NTFS_GLOBAL_DATAPNTFS_GLOBAL_DATA
 
typedef enum ATTRIBUTE_TYPEPATTRIBUTE_TYPE
 
typedef struct NTFS_RECORD_HEADERPNTFS_RECORD_HEADER
 
typedef struct _FILE_RECORD_HEADER FILE_RECORD_HEADER
 
typedef struct _FILE_RECORD_HEADERPFILE_RECORD_HEADER
 
typedef struct NTFS_ATTR_RECORDPNTFS_ATTR_RECORD
 
typedef struct NTFS_ATTRIBUTE_LIST_ITEMPNTFS_ATTRIBUTE_LIST_ITEM
 
typedef struct STANDARD_INFORMATIONPSTANDARD_INFORMATION
 
typedef struct ATTRIBUTE_LISTPATTRIBUTE_LIST
 
typedef struct FILENAME_ATTRIBUTEPFILENAME_ATTRIBUTE
 
typedef struct INDEX_HEADER_ATTRIBUTEPINDEX_HEADER_ATTRIBUTE
 
typedef struct INDEX_ROOT_ATTRIBUTEPINDEX_ROOT_ATTRIBUTE
 
typedef struct INDEX_BUFFERPINDEX_BUFFER
 
typedef struct INDEX_ENTRY_ATTRIBUTEPINDEX_ENTRY_ATTRIBUTE
 
typedef struct _B_TREE_FILENAME_NODE B_TREE_FILENAME_NODE
 
typedef struct _B_TREE_KEY B_TREE_KEY
 
typedef struct _B_TREE_KEYPB_TREE_KEY
 
typedef struct _B_TREE_FILENAME_NODEPB_TREE_FILENAME_NODE
 
typedef struct B_TREEPB_TREE
 
typedef struct VOLINFO_ATTRIBUTEPVOLINFO_ATTRIBUTE
 
typedef struct REPARSE_POINT_ATTRIBUTEPREPARSE_POINT_ATTRIBUTE
 
typedef struct NTFS_IRP_CONTEXTPNTFS_IRP_CONTEXT
 
typedef struct _NTFS_ATTR_CONTEXT NTFS_ATTR_CONTEXT
 
typedef struct _NTFS_ATTR_CONTEXTPNTFS_ATTR_CONTEXT
 
typedef struct _FCB NTFS_FCB
 
typedef struct _FCBPNTFS_FCB
 
typedef struct _FIND_ATTR_CONTXT FIND_ATTR_CONTXT
 
typedef struct _FIND_ATTR_CONTXTPFIND_ATTR_CONTXT
 
typedef struct FIXUP_ARRAYPFIXUP_ARRAY
 

Enumerations

enum  ATTRIBUTE_TYPE {
  AttributeStandardInformation = 0x10 , AttributeAttributeList = 0x20 , AttributeFileName = 0x30 , AttributeObjectId = 0x40 ,
  AttributeSecurityDescriptor = 0x50 , AttributeVolumeName = 0x60 , AttributeVolumeInformation = 0x70 , AttributeData = 0x80 ,
  AttributeIndexRoot = 0x90 , AttributeIndexAllocation = 0xA0 , AttributeBitmap = 0xB0 , AttributeReparsePoint = 0xC0 ,
  AttributeEAInformation = 0xD0 , AttributeEA = 0xE0 , AttributePropertySet = 0xF0 , AttributeLoggedUtilityStream = 0x100 ,
  AttributeEnd = 0xFFFFFFFF , AttributeStandardInformation = 0x10 , AttributeAttributeList = 0x20 , AttributeFileName = 0x30 ,
  AttributeObjectId = 0x40 , AttributeSecurityDescriptor = 0x50 , AttributeVolumeName = 0x60 , AttributeVolumeInformation = 0x70 ,
  AttributeData = 0x80 , AttributeIndexRoot = 0x90 , AttributeIndexAllocation = 0xA0 , AttributeBitmap = 0xB0 ,
  AttributeReparsePoint = 0xC0 , AttributeEAInformation = 0xD0 , AttributeEA = 0xE0 , AttributePropertySet = 0xF0 ,
  AttributeLoggedUtilityStream = 0x100 , AttributeEnd = 0xFFFFFFFF
}
 

Functions

FORCEINLINE NTSTATUS NtfsMarkIrpContextForQueue (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS AddBitmap (PNTFS_VCB Vcb, PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress, PCWSTR Name, USHORT NameLength)
 
NTSTATUS AddData (PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress)
 
NTSTATUS AddRun (PNTFS_VCB Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, ULONGLONG NextAssignedCluster, ULONG RunLength)
 
NTSTATUS AddIndexAllocation (PNTFS_VCB Vcb, PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress, PCWSTR Name, USHORT NameLength)
 
NTSTATUS AddIndexRoot (PNTFS_VCB Vcb, PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress, PINDEX_ROOT_ATTRIBUTE NewIndexRoot, ULONG RootLength, PCWSTR Name, USHORT NameLength)
 
NTSTATUS AddFileName (PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress, PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, BOOLEAN CaseSensitive, PULONGLONG ParentMftIndex)
 
NTSTATUS AddStandardInformation (PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress)
 
NTSTATUS ConvertDataRunsToLargeMCB (PUCHAR DataRun, PLARGE_MCB DataRunsMCB, PULONGLONG pNextVBN)
 
NTSTATUS ConvertLargeMCBToDataRuns (PLARGE_MCB DataRunsMCB, PUCHAR RunBuffer, ULONG MaxBufferSize, PULONG UsedBufferSize)
 
PUCHAR DecodeRun (PUCHAR DataRun, LONGLONG *DataRunOffset, ULONGLONG *DataRunLength)
 
ULONG GetFileNameAttributeLength (PFILENAME_ATTRIBUTE FileNameAttribute)
 
VOID NtfsDumpDataRuns (PVOID StartOfRun, ULONGLONG CurrentLCN)
 
VOID NtfsDumpFileAttributes (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
 
PSTANDARD_INFORMATION GetStandardInformationFromRecord (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
 
PFILENAME_ATTRIBUTE GetFileNameFromRecord (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord, UCHAR NameType)
 
UCHAR GetPackedByteCount (LONGLONG NumberToPack, BOOLEAN IsSigned)
 
NTSTATUS GetLastClusterInDataRun (PDEVICE_EXTENSION Vcb, PNTFS_ATTR_RECORD Attribute, PULONGLONG LastCluster)
 
PFILENAME_ATTRIBUTE GetBestFileNameFromRecord (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
 
NTSTATUS FindFirstAttributeListItem (PFIND_ATTR_CONTXT Context, PNTFS_ATTRIBUTE_LIST_ITEM *Item)
 
NTSTATUS FindNextAttributeListItem (PFIND_ATTR_CONTXT Context, PNTFS_ATTRIBUTE_LIST_ITEM *Item)
 
NTSTATUS FindFirstAttribute (PFIND_ATTR_CONTXT Context, PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord, BOOLEAN OnlyResident, PNTFS_ATTR_RECORD *Attribute)
 
NTSTATUS FindNextAttribute (PFIND_ATTR_CONTXT Context, PNTFS_ATTR_RECORD *Attribute)
 
VOID FindCloseAttribute (PFIND_ATTR_CONTXT Context)
 
NTSTATUS FreeClusters (PNTFS_VCB Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, ULONG ClustersToFree)
 
NTSTATUS NtfsReadDisk (IN PDEVICE_OBJECT DeviceObject, IN LONGLONG StartingOffset, IN ULONG Length, IN ULONG SectorSize, IN OUT PUCHAR Buffer, IN BOOLEAN Override)
 
NTSTATUS NtfsWriteDisk (IN PDEVICE_OBJECT DeviceObject, IN LONGLONG StartingOffset, IN ULONG Length, IN ULONG SectorSize, IN const PUCHAR Buffer)
 
NTSTATUS NtfsReadSectors (IN PDEVICE_OBJECT DeviceObject, IN ULONG DiskSector, IN ULONG SectorCount, IN ULONG SectorSize, IN OUT PUCHAR Buffer, IN BOOLEAN Override)
 
NTSTATUS NtfsDeviceIoControl (IN PDEVICE_OBJECT DeviceObject, IN ULONG ControlCode, IN PVOID InputBuffer, IN ULONG InputBufferSize, IN OUT PVOID OutputBuffer, IN OUT PULONG OutputBufferSize, IN BOOLEAN Override)
 
LONG CompareTreeKeys (PB_TREE_KEY Key1, PB_TREE_KEY Key2, BOOLEAN CaseSensitive)
 
NTSTATUS CreateBTreeFromIndex (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecordWithIndex, PNTFS_ATTR_CONTEXT IndexRootContext, PINDEX_ROOT_ATTRIBUTE IndexRoot, PB_TREE *NewTree)
 
NTSTATUS CreateIndexRootFromBTree (PDEVICE_EXTENSION DeviceExt, PB_TREE Tree, ULONG MaxIndexSize, PINDEX_ROOT_ATTRIBUTE *IndexRoot, ULONG *Length)
 
NTSTATUS DemoteBTreeRoot (PB_TREE Tree)
 
VOID DestroyBTree (PB_TREE Tree)
 
VOID DestroyBTreeNode (PB_TREE_FILENAME_NODE Node)
 
VOID DumpBTree (PB_TREE Tree)
 
VOID DumpBTreeKey (PB_TREE Tree, PB_TREE_KEY Key, ULONG Number, ULONG Depth)
 
VOID DumpBTreeNode (PB_TREE Tree, PB_TREE_FILENAME_NODE Node, ULONG Number, ULONG Depth)
 
NTSTATUS CreateEmptyBTree (PB_TREE *NewTree)
 
ULONGLONG GetAllocationOffsetFromVCN (PDEVICE_EXTENSION DeviceExt, ULONG IndexBufferSize, ULONGLONG Vcn)
 
ULONGLONG GetIndexEntryVCN (PINDEX_ENTRY_ATTRIBUTE IndexEntry)
 
ULONG GetSizeOfIndexEntries (PB_TREE_FILENAME_NODE Node)
 
NTSTATUS NtfsInsertKey (PB_TREE Tree, ULONGLONG FileReference, PFILENAME_ATTRIBUTE FileNameAttribute, PB_TREE_FILENAME_NODE Node, BOOLEAN CaseSensitive, ULONG MaxIndexRootSize, ULONG IndexRecordSize, PB_TREE_KEY *MedianKey, PB_TREE_FILENAME_NODE *NewRightHandSibling)
 
NTSTATUS SplitBTreeNode (PB_TREE Tree, PB_TREE_FILENAME_NODE Node, PB_TREE_KEY *MedianKey, PB_TREE_FILENAME_NODE *NewRightHandSibling, BOOLEAN CaseSensitive)
 
NTSTATUS UpdateIndexAllocation (PDEVICE_EXTENSION DeviceExt, PB_TREE Tree, ULONG IndexBufferSize, PFILE_RECORD_HEADER FileRecord)
 
NTSTATUS UpdateIndexNode (PDEVICE_EXTENSION DeviceExt, PFILE_RECORD_HEADER FileRecord, PB_TREE_FILENAME_NODE Node, ULONG IndexBufferSize, PNTFS_ATTR_CONTEXT IndexAllocationContext, ULONG IndexAllocationOffset)
 
NTSTATUS NtfsCleanup (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NtfsCloseFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
 
NTSTATUS NtfsClose (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NtfsCreate (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NtfsCreateDirectory (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, BOOLEAN CaseSensitive, BOOLEAN CanWait)
 
PFILE_RECORD_HEADER NtfsCreateEmptyFileRecord (PDEVICE_EXTENSION DeviceExt)
 
NTSTATUS NtfsCreateFileRecord (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, BOOLEAN CaseSensitive, BOOLEAN CanWait)
 
NTSTATUS NtfsDeviceControl (PNTFS_IRP_CONTEXT IrpContext)
 
ULONGLONG NtfsGetFileSize (PDEVICE_EXTENSION DeviceExt, PFILE_RECORD_HEADER FileRecord, PCWSTR Stream, ULONG StreamLength, PULONGLONG AllocatedSize)
 
NTSTATUS NtfsDirectoryControl (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NTAPI NtfsFsdDispatch (PDEVICE_OBJECT DeviceObject, PIRP Irp)
 
BOOLEAN NTAPI NtfsAcqLazyWrite (PVOID Context, BOOLEAN Wait)
 
VOID NTAPI NtfsRelLazyWrite (PVOID Context)
 
BOOLEAN NTAPI NtfsAcqReadAhead (PVOID Context, BOOLEAN Wait)
 
VOID NTAPI NtfsRelReadAhead (PVOID Context)
 
PNTFS_FCB NtfsCreateFCB (PCWSTR FileName, PCWSTR Stream, PNTFS_VCB Vcb)
 
VOID NtfsDestroyFCB (PNTFS_FCB Fcb)
 
BOOLEAN NtfsFCBIsDirectory (PNTFS_FCB Fcb)
 
BOOLEAN NtfsFCBIsReparsePoint (PNTFS_FCB Fcb)
 
BOOLEAN NtfsFCBIsCompressed (PNTFS_FCB Fcb)
 
BOOLEAN NtfsFCBIsEncrypted (PNTFS_FCB Fcb)
 
BOOLEAN NtfsFCBIsRoot (PNTFS_FCB Fcb)
 
VOID NtfsGrabFCB (PNTFS_VCB Vcb, PNTFS_FCB Fcb)
 
VOID NtfsReleaseFCB (PNTFS_VCB Vcb, PNTFS_FCB Fcb)
 
VOID NtfsAddFCBToTable (PNTFS_VCB Vcb, PNTFS_FCB Fcb)
 
PNTFS_FCB NtfsGrabFCBFromTable (PNTFS_VCB Vcb, PCWSTR FileName)
 
NTSTATUS NtfsFCBInitializeCache (PNTFS_VCB Vcb, PNTFS_FCB Fcb)
 
PNTFS_FCB NtfsMakeRootFCB (PNTFS_VCB Vcb)
 
PNTFS_FCB NtfsOpenRootFCB (PNTFS_VCB Vcb)
 
NTSTATUS NtfsAttachFCBToFileObject (PNTFS_VCB Vcb, PNTFS_FCB Fcb, PFILE_OBJECT FileObject)
 
NTSTATUS NtfsGetFCBForFile (PNTFS_VCB Vcb, PNTFS_FCB *pParentFCB, PNTFS_FCB *pFCB, PCWSTR pFileName, BOOLEAN CaseSensitive)
 
NTSTATUS NtfsReadFCBAttribute (PNTFS_VCB Vcb, PNTFS_FCB pFCB, ULONG Type, PCWSTR Name, ULONG NameLength, PVOID *Data)
 
NTSTATUS NtfsMakeFCBFromDirEntry (PNTFS_VCB Vcb, PNTFS_FCB DirectoryFCB, PUNICODE_STRING Name, PCWSTR Stream, PFILE_RECORD_HEADER Record, ULONGLONG MFTIndex, PNTFS_FCB *fileFCB)
 
NTSTATUS NtfsQueryInformation (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NtfsSetEndOfFile (PNTFS_FCB Fcb, PFILE_OBJECT FileObject, PDEVICE_EXTENSION DeviceExt, ULONG IrpFlags, BOOLEAN CaseSensitive, PLARGE_INTEGER NewFileSize)
 
NTSTATUS NtfsSetInformation (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NtfsFileSystemControl (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NtfsAddFilenameToDirectory (PDEVICE_EXTENSION DeviceExt, ULONGLONG DirectoryMftIndex, ULONGLONG FileReferenceNumber, PFILENAME_ATTRIBUTE FilenameAttribute, BOOLEAN CaseSensitive)
 
NTSTATUS AddNewMftEntry (PFILE_RECORD_HEADER FileRecord, PDEVICE_EXTENSION DeviceExt, PULONGLONG DestinationIndex, BOOLEAN CanWait)
 
VOID NtfsDumpData (ULONG_PTR Buffer, ULONG Length)
 
PNTFS_ATTR_CONTEXT PrepareAttributeContext (PNTFS_ATTR_RECORD AttrRecord)
 
VOID ReleaseAttributeContext (PNTFS_ATTR_CONTEXT Context)
 
ULONG ReadAttribute (PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
 
NTSTATUS WriteAttribute (PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, const PUCHAR Buffer, ULONG Length, PULONG LengthWritten, PFILE_RECORD_HEADER FileRecord)
 
ULONGLONG AttributeDataLength (PNTFS_ATTR_RECORD AttrRecord)
 
NTSTATUS InternalSetResidentAttributeLength (PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_CONTEXT AttrContext, PFILE_RECORD_HEADER FileRecord, ULONG AttrOffset, ULONG DataSize)
 
PNTFS_ATTR_RECORD MoveAttributes (PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_RECORD FirstAttributeToMove, ULONG FirstAttributeOffset, ULONG_PTR MoveTo)
 
NTSTATUS SetAttributeDataLength (PFILE_OBJECT FileObject, PNTFS_FCB Fcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
 
VOID SetFileRecordEnd (PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttrEnd, ULONG EndMarker)
 
NTSTATUS SetNonResidentAttributeDataLength (PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
 
NTSTATUS SetResidentAttributeDataLength (PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
 
ULONGLONG AttributeAllocatedLength (PNTFS_ATTR_RECORD AttrRecord)
 
BOOLEAN CompareFileName (PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive)
 
NTSTATUS UpdateMftMirror (PNTFS_VCB Vcb)
 
NTSTATUS ReadFileRecord (PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
 
NTSTATUS UpdateIndexEntryFileNameSize (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER MftRecord, PCHAR IndexRecord, ULONG IndexBlockSize, PINDEX_ENTRY_ATTRIBUTE FirstEntry, PINDEX_ENTRY_ATTRIBUTE LastEntry, PUNICODE_STRING FileName, PULONG StartEntry, PULONG CurrentEntry, BOOLEAN DirSearch, ULONGLONG NewDataSize, ULONGLONG NewAllocatedSize, BOOLEAN CaseSensitive)
 
NTSTATUS UpdateFileNameRecord (PDEVICE_EXTENSION Vcb, ULONGLONG ParentMFTIndex, PUNICODE_STRING FileName, BOOLEAN DirSearch, ULONGLONG NewDataSize, ULONGLONG NewAllocationSize, BOOLEAN CaseSensitive)
 
NTSTATUS UpdateFileRecord (PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
 
NTSTATUS FindAttribute (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER MftRecord, ULONG Type, PCWSTR Name, ULONG NameLength, PNTFS_ATTR_CONTEXT *AttrCtx, PULONG Offset)
 
VOID ReadVCN (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER file, ATTRIBUTE_TYPE type, ULONGLONG vcn, ULONG count, PVOID buffer)
 
NTSTATUS FixupUpdateSequenceArray (PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
 
NTSTATUS AddFixupArray (PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
 
NTSTATUS ReadLCN (PDEVICE_EXTENSION Vcb, ULONGLONG lcn, ULONG count, PVOID buffer)
 
VOID EnumerAttribute (PFILE_RECORD_HEADER file, PDEVICE_EXTENSION Vcb, PDEVICE_OBJECT DeviceObject)
 
NTSTATUS NtfsLookupFile (PDEVICE_EXTENSION Vcb, PUNICODE_STRING PathName, BOOLEAN CaseSensitive, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex)
 
NTSTATUS NtfsLookupFileAt (PDEVICE_EXTENSION Vcb, PUNICODE_STRING PathName, BOOLEAN CaseSensitive, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex, ULONGLONG CurrentMFTIndex)
 
VOID NtfsDumpFileRecord (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
 
NTSTATUS NtfsFindFileAt (PDEVICE_EXTENSION Vcb, PUNICODE_STRING SearchPattern, PULONG FirstEntry, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex, ULONGLONG CurrentMFTIndex, BOOLEAN CaseSensitive)
 
NTSTATUS NtfsFindMftRecord (PDEVICE_EXTENSION Vcb, ULONGLONG MFTIndex, PUNICODE_STRING FileName, PULONG FirstEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
 
BOOLEAN NtfsIsIrpTopLevel (PIRP Irp)
 
PNTFS_IRP_CONTEXT NtfsAllocateIrpContext (PDEVICE_OBJECT DeviceObject, PIRP Irp)
 
PVOID NtfsGetUserBuffer (PIRP Irp, BOOLEAN Paging)
 
NTSTATUS NtfsLockUserBuffer (IN PIRP Irp, IN ULONG Length, IN LOCK_OPERATION Operation)
 
VOID NtfsFileFlagsToAttributes (ULONG NtfsAttributes, PULONG FileAttributes)
 
NTSTATUS NtfsRead (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NtfsWrite (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NtfsAllocateClusters (PDEVICE_EXTENSION DeviceExt, ULONG FirstDesiredCluster, ULONG DesiredClusters, PULONG FirstAssignedCluster, PULONG AssignedClusters)
 
ULONGLONG NtfsGetFreeClusters (PDEVICE_EXTENSION DeviceExt)
 
NTSTATUS NtfsQueryVolumeInformation (PNTFS_IRP_CONTEXT IrpContext)
 
NTSTATUS NtfsSetVolumeInformation (PNTFS_IRP_CONTEXT IrpContext)
 
VOID NTAPI NtfsInitializeFunctionPointers (PDRIVER_OBJECT DriverObject)
 

Variables

PNTFS_GLOBAL_DATA NtfsGlobalData
 
DRIVER_DISPATCH NtfsFsdDispatch
 
FAST_IO_CHECK_IF_POSSIBLE NtfsFastIoCheckIfPossible
 
FAST_IO_READ NtfsFastIoRead
 
FAST_IO_WRITE NtfsFastIoWrite
 
DRIVER_INITIALIZE DriverEntry
 

Macro Definition Documentation

◆ ATTR_RECORD_ALIGNMENT

#define ATTR_RECORD_ALIGNMENT   8

Definition at line 320 of file ntfs.h.

◆ CACHEPAGESIZE

#define CACHEPAGESIZE (   pDeviceExt)
Value:
((pDeviceExt)->NtfsInfo.UCHARsPerCluster > PAGE_SIZE ? \
(pDeviceExt)->NtfsInfo.UCHARsPerCluster : PAGE_SIZE)
#define PAGE_SIZE
Definition: env_spec_w32.h:49

Definition at line 8 of file ntfs.h.

◆ COLLATION_BINARY

#define COLLATION_BINARY   0x00

Definition at line 200 of file ntfs.h.

◆ COLLATION_FILE_NAME

#define COLLATION_FILE_NAME   0x01

Definition at line 201 of file ntfs.h.

◆ COLLATION_NTOFS_SECURITY_HASH

#define COLLATION_NTOFS_SECURITY_HASH   0x12

Definition at line 205 of file ntfs.h.

◆ COLLATION_NTOFS_SID

#define COLLATION_NTOFS_SID   0x11

Definition at line 204 of file ntfs.h.

◆ COLLATION_NTOFS_ULONG

#define COLLATION_NTOFS_ULONG   0x10

Definition at line 203 of file ntfs.h.

◆ COLLATION_NTOFS_ULONGS

#define COLLATION_NTOFS_ULONGS   0x13

Definition at line 206 of file ntfs.h.

◆ COLLATION_UNICODE_STRING

#define COLLATION_UNICODE_STRING   0x02

Definition at line 202 of file ntfs.h.

◆ DATA_RUN_ALIGNMENT

#define DATA_RUN_ALIGNMENT   4

Definition at line 323 of file ntfs.h.

◆ DEVICE_NAME

#define DEVICE_NAME   L"\\Ntfs"

Definition at line 22 of file ntfs.h.

◆ FCB_CACHE_INITIALIZED

#define FCB_CACHE_INITIALIZED   0x0001

Definition at line 508 of file ntfs.h.

◆ FCB_IS_VOLUME

#define FCB_IS_VOLUME   0x0004

Definition at line 510 of file ntfs.h.

◆ FCB_IS_VOLUME_STREAM

#define FCB_IS_VOLUME_STREAM   0x0002

Definition at line 509 of file ntfs.h.

◆ FILE_RECORD_END

#define FILE_RECORD_END   0x11477982

Definition at line 182 of file ntfs.h.

◆ FRH_DIRECTORY

#define FRH_DIRECTORY   0x0002 /* Record is a directory */

Definition at line 268 of file ntfs.h.

◆ FRH_IN_USE

#define FRH_IN_USE   0x0001 /* Record is in use */

Definition at line 267 of file ntfs.h.

◆ FRH_UNKNOWN1

#define FRH_UNKNOWN1   0x0004 /* Don't know */

Definition at line 269 of file ntfs.h.

◆ FRH_UNKNOWN2

#define FRH_UNKNOWN2   0x0008 /* Don't know */

Definition at line 270 of file ntfs.h.

◆ INDEX_NODE_LARGE

#define INDEX_NODE_LARGE   0x1

Definition at line 212 of file ntfs.h.

◆ INDEX_NODE_SMALL

#define INDEX_NODE_SMALL   0x0

Definition at line 211 of file ntfs.h.

◆ INDEX_ROOT_LARGE

#define INDEX_ROOT_LARGE   0x1

Definition at line 209 of file ntfs.h.

◆ INDEX_ROOT_SMALL

#define INDEX_ROOT_SMALL   0x0

Definition at line 208 of file ntfs.h.

◆ IRPCONTEXT_CANWAIT

#define IRPCONTEXT_CANWAIT   0x1

Definition at line 474 of file ntfs.h.

◆ IRPCONTEXT_COMPLETE

#define IRPCONTEXT_COMPLETE   0x2

Definition at line 475 of file ntfs.h.

◆ IRPCONTEXT_QUEUE

#define IRPCONTEXT_QUEUE   0x4

Definition at line 476 of file ntfs.h.

◆ MAX_PATH

#define MAX_PATH   260

Definition at line 511 of file ntfs.h.

◆ NRH_FILE_TYPE

#define NRH_FILE_TYPE   0x454C4946 /* 'FILE' */

Definition at line 246 of file ntfs.h.

◆ NRH_INDX_TYPE

#define NRH_INDX_TYPE   0x58444E49 /* 'INDX' */

Definition at line 247 of file ntfs.h.

◆ NTFS_FILE_ATTRDEF

#define NTFS_FILE_ATTRDEF   4

Definition at line 188 of file ntfs.h.

◆ NTFS_FILE_BADCLUS

#define NTFS_FILE_BADCLUS   8

Definition at line 192 of file ntfs.h.

◆ NTFS_FILE_BITMAP

#define NTFS_FILE_BITMAP   6

Definition at line 190 of file ntfs.h.

◆ NTFS_FILE_BOOT

#define NTFS_FILE_BOOT   7

Definition at line 191 of file ntfs.h.

◆ NTFS_FILE_EXTEND

#define NTFS_FILE_EXTEND   11

Definition at line 195 of file ntfs.h.

◆ NTFS_FILE_FIRST_USER_FILE

#define NTFS_FILE_FIRST_USER_FILE   16

Definition at line 196 of file ntfs.h.

◆ NTFS_FILE_LOGFILE

#define NTFS_FILE_LOGFILE   2

Definition at line 186 of file ntfs.h.

◆ NTFS_FILE_MFT

#define NTFS_FILE_MFT   0

Definition at line 184 of file ntfs.h.

◆ NTFS_FILE_MFTMIRR

#define NTFS_FILE_MFTMIRR   1

Definition at line 185 of file ntfs.h.

◆ NTFS_FILE_NAME_DOS

#define NTFS_FILE_NAME_DOS   2

Definition at line 219 of file ntfs.h.

◆ NTFS_FILE_NAME_POSIX

#define NTFS_FILE_NAME_POSIX   0

Definition at line 217 of file ntfs.h.

◆ NTFS_FILE_NAME_WIN32

#define NTFS_FILE_NAME_WIN32   1

Definition at line 218 of file ntfs.h.

◆ NTFS_FILE_NAME_WIN32_AND_DOS

#define NTFS_FILE_NAME_WIN32_AND_DOS   3

Definition at line 220 of file ntfs.h.

◆ NTFS_FILE_QUOTA

#define NTFS_FILE_QUOTA   9

Definition at line 193 of file ntfs.h.

◆ NTFS_FILE_ROOT

#define NTFS_FILE_ROOT   5

Definition at line 189 of file ntfs.h.

◆ NTFS_FILE_TYPE_ARCHIVE

#define NTFS_FILE_TYPE_ARCHIVE   0x20

Definition at line 225 of file ntfs.h.

◆ NTFS_FILE_TYPE_COMPRESSED

#define NTFS_FILE_TYPE_COMPRESSED   0x800

Definition at line 229 of file ntfs.h.

◆ NTFS_FILE_TYPE_DIRECTORY

#define NTFS_FILE_TYPE_DIRECTORY   0x10000000

Definition at line 232 of file ntfs.h.

◆ NTFS_FILE_TYPE_ENCRYPTED

#define NTFS_FILE_TYPE_ENCRYPTED   0x4000

Definition at line 231 of file ntfs.h.

◆ NTFS_FILE_TYPE_HIDDEN

#define NTFS_FILE_TYPE_HIDDEN   0x2

Definition at line 223 of file ntfs.h.

◆ NTFS_FILE_TYPE_OFFLINE

#define NTFS_FILE_TYPE_OFFLINE   0x1000

Definition at line 230 of file ntfs.h.

◆ NTFS_FILE_TYPE_READ_ONLY

#define NTFS_FILE_TYPE_READ_ONLY   0x1

Definition at line 222 of file ntfs.h.

◆ NTFS_FILE_TYPE_REPARSE

#define NTFS_FILE_TYPE_REPARSE   0x400

Definition at line 228 of file ntfs.h.

◆ NTFS_FILE_TYPE_SPARSE

#define NTFS_FILE_TYPE_SPARSE   0x200

Definition at line 227 of file ntfs.h.

◆ NTFS_FILE_TYPE_SYSTEM

#define NTFS_FILE_TYPE_SYSTEM   0x4

Definition at line 224 of file ntfs.h.

◆ NTFS_FILE_TYPE_TEMPORARY

#define NTFS_FILE_TYPE_TEMPORARY   0x100

Definition at line 226 of file ntfs.h.

◆ NTFS_FILE_UPCASE

#define NTFS_FILE_UPCASE   10

Definition at line 194 of file ntfs.h.

◆ NTFS_FILE_VOLUME

#define NTFS_FILE_VOLUME   3

Definition at line 187 of file ntfs.h.

◆ NTFS_INDEX_ENTRY_END

#define NTFS_INDEX_ENTRY_END   2

Definition at line 215 of file ntfs.h.

◆ NTFS_INDEX_ENTRY_NODE

#define NTFS_INDEX_ENTRY_NODE   1

Definition at line 214 of file ntfs.h.

◆ NTFS_MFT_MASK

#define NTFS_MFT_MASK   0x0000FFFFFFFFFFFFULL

Definition at line 198 of file ntfs.h.

◆ NTFS_TYPE_CCB

#define NTFS_TYPE_CCB   '20SF'

Definition at line 87 of file ntfs.h.

◆ NTFS_TYPE_FCB

#define NTFS_TYPE_FCB   '30SF'

Definition at line 88 of file ntfs.h.

◆ NTFS_TYPE_GLOBAL_DATA

#define NTFS_TYPE_GLOBAL_DATA   '70SF'

Definition at line 91 of file ntfs.h.

◆ NTFS_TYPE_IRP_CONTEXT

#define NTFS_TYPE_IRP_CONTEXT   '60SF'

Definition at line 90 of file ntfs.h.

◆ NTFS_TYPE_VCB

#define NTFS_TYPE_VCB   '50SF'

Definition at line 89 of file ntfs.h.

◆ RA_INDEXED

#define RA_INDEXED   0x01

Definition at line 235 of file ntfs.h.

◆ ROUND_DOWN

#define ROUND_DOWN (   N,
  S 
)    ((N) - ((N) % (S)))

Definition at line 20 of file ntfs.h.

◆ ROUND_UP

#define ROUND_UP (   N,
  S 
)    ((((N) + (S) - 1) / (S)) * (S))

Definition at line 19 of file ntfs.h.

◆ TAG_ATT_CTXT

#define TAG_ATT_CTXT   'aftN'

Definition at line 16 of file ntfs.h.

◆ TAG_CCB

#define TAG_CCB   'CftN'

Definition at line 13 of file ntfs.h.

◆ TAG_FCB

#define TAG_FCB   'FftN'

Definition at line 14 of file ntfs.h.

◆ TAG_FILE_REC

#define TAG_FILE_REC   'rftN'

Definition at line 17 of file ntfs.h.

◆ TAG_IRP_CTXT

#define TAG_IRP_CTXT   'iftN'

Definition at line 15 of file ntfs.h.

◆ TAG_NTFS

#define TAG_NTFS   '0ftN'

Definition at line 12 of file ntfs.h.

◆ VALUE_OFFSET_ALIGNMENT

#define VALUE_OFFSET_ALIGNMENT   4

Definition at line 326 of file ntfs.h.

◆ VCB_VOLUME_LOCKED

#define VCB_VOLUME_LOCKED   0x0001

Definition at line 127 of file ntfs.h.

Typedef Documentation

◆ B_TREE_FILENAME_NODE

Definition at line 431 of file ntfs.h.

◆ B_TREE_KEY

◆ BIOS_PARAMETERS_BLOCK

◆ BOOT_SECTOR

◆ EXTENDED_BIOS_PARAMETERS_BLOCK

◆ FILE_RECORD_HEADER

◆ FIND_ATTR_CONTXT

◆ NTFS_ATTR_CONTEXT

◆ NTFS_FCB

typedef struct _FCB NTFS_FCB

◆ NTFS_INFO

◆ NTFS_VCB

◆ PATTRIBUTE_LIST

◆ PATTRIBUTE_TYPE

◆ PB_TREE

typedef struct B_TREE * PB_TREE

◆ PB_TREE_FILENAME_NODE

◆ PB_TREE_KEY

◆ PBIOS_PARAMETERS_BLOCK

◆ PBOOT_SECTOR

◆ PDEVICE_EXTENSION

◆ PEXTENDED_BIOS_PARAMETERS_BLOCK

◆ PFILE_RECORD_HEADER

◆ PFILENAME_ATTRIBUTE

◆ PFIND_ATTR_CONTXT

◆ PFIXUP_ARRAY

◆ PINDEX_BUFFER

◆ PINDEX_ENTRY_ATTRIBUTE

◆ PINDEX_HEADER_ATTRIBUTE

◆ PINDEX_ROOT_ATTRIBUTE

◆ PNTFS_ATTR_CONTEXT

◆ PNTFS_ATTR_RECORD

◆ PNTFS_ATTRIBUTE_LIST_ITEM

◆ PNTFS_CCB

◆ PNTFS_FCB

typedef struct _FCB * PNTFS_FCB

◆ PNTFS_GLOBAL_DATA

◆ PNTFS_INFO

◆ PNTFS_IRP_CONTEXT

◆ PNTFS_RECORD_HEADER

◆ PNTFS_VCB

◆ PNTFSIDENTIFIER

◆ PREPARSE_POINT_ATTRIBUTE

◆ PSTANDARD_INFORMATION

◆ PVOLINFO_ATTRIBUTE

Enumeration Type Documentation

◆ ATTRIBUTE_TYPE

Enumerator
AttributeStandardInformation 
AttributeAttributeList 
AttributeFileName 
AttributeObjectId 
AttributeSecurityDescriptor 
AttributeVolumeName 
AttributeVolumeInformation 
AttributeData 
AttributeIndexRoot 
AttributeIndexAllocation 
AttributeBitmap 
AttributeReparsePoint 
AttributeEAInformation 
AttributeEA 
AttributePropertySet 
AttributeLoggedUtilityStream 
AttributeEnd 
AttributeStandardInformation 
AttributeAttributeList 
AttributeFileName 
AttributeObjectId 
AttributeSecurityDescriptor 
AttributeVolumeName 
AttributeVolumeInformation 
AttributeData 
AttributeIndexRoot 
AttributeIndexAllocation 
AttributeBitmap 
AttributeReparsePoint 
AttributeEAInformation 
AttributeEA 
AttributePropertySet 
AttributeLoggedUtilityStream 
AttributeEnd 

Definition at line 159 of file ntfs.h.

160{
163 AttributeFileName = 0x30,
164 AttributeObjectId = 0x40,
166 AttributeVolumeName = 0x60,
168 AttributeData = 0x80,
169 AttributeIndexRoot = 0x90,
171 AttributeBitmap = 0xB0,
174 AttributeEA = 0xE0,
177 AttributeEnd = 0xFFFFFFFF
enum ATTRIBUTE_TYPE * PATTRIBUTE_TYPE
ATTRIBUTE_TYPE
Definition: ntfs.h:160
@ AttributeVolumeName
Definition: ntfs.h:166
@ AttributeEnd
Definition: ntfs.h:177
@ AttributeIndexRoot
Definition: ntfs.h:169
@ AttributePropertySet
Definition: ntfs.h:175
@ AttributeReparsePoint
Definition: ntfs.h:172
@ AttributeFileName
Definition: ntfs.h:163
@ AttributeEAInformation
Definition: ntfs.h:173
@ AttributeStandardInformation
Definition: ntfs.h:161
@ AttributeEA
Definition: ntfs.h:174
@ AttributeAttributeList
Definition: ntfs.h:162
@ AttributeVolumeInformation
Definition: ntfs.h:167
@ AttributeSecurityDescriptor
Definition: ntfs.h:165
@ AttributeIndexAllocation
Definition: ntfs.h:170
@ AttributeObjectId
Definition: ntfs.h:164
@ AttributeLoggedUtilityStream
Definition: ntfs.h:176
@ AttributeData
Definition: ntfs.h:168
@ AttributeBitmap
Definition: ntfs.h:171

Function Documentation

◆ AddBitmap()

NTSTATUS AddBitmap ( PNTFS_VCB  Vcb,
PFILE_RECORD_HEADER  FileRecord,
PNTFS_ATTR_RECORD  AttributeAddress,
PCWSTR  Name,
USHORT  NameLength 
)

Definition at line 72 of file attrib.c.

77{
78 ULONG AttributeLength;
79 // Calculate the header length
80 ULONG ResidentHeaderLength = FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.Reserved) + sizeof(UCHAR);
81 ULONG FileRecordEnd = AttributeAddress->Length;
82 ULONG NameOffset;
83 ULONG ValueOffset;
84 // We'll start out with 8 bytes of bitmap data
86 ULONG BytesAvailable;
87
88 if (AttributeAddress->Type != AttributeEnd)
89 {
90 DPRINT1("FIXME: Can only add $BITMAP attribute to the end of a file record.\n");
92 }
93
94 NameOffset = ResidentHeaderLength;
95
96 // Calculate ValueOffset, which will be aligned to a 4-byte boundary
97 ValueOffset = ALIGN_UP_BY(NameOffset + (sizeof(WCHAR) * NameLength), VALUE_OFFSET_ALIGNMENT);
98
99 // Calculate length of attribute
100 AttributeLength = ValueOffset + ValueLength;
101 AttributeLength = ALIGN_UP_BY(AttributeLength, ATTR_RECORD_ALIGNMENT);
102
103 // Make sure the file record is large enough for the new attribute
104 BytesAvailable = Vcb->NtfsInfo.BytesPerFileRecord - FileRecord->BytesInUse;
105 if (BytesAvailable < AttributeLength)
106 {
107 DPRINT1("FIXME: Not enough room in file record for index allocation attribute!\n");
109 }
110
111 // Set Attribute fields
112 RtlZeroMemory(AttributeAddress, AttributeLength);
113
114 AttributeAddress->Type = AttributeBitmap;
115 AttributeAddress->Length = AttributeLength;
116 AttributeAddress->NameLength = NameLength;
117 AttributeAddress->NameOffset = NameOffset;
118 AttributeAddress->Instance = FileRecord->NextAttributeNumber++;
119
120 AttributeAddress->Resident.ValueLength = ValueLength;
121 AttributeAddress->Resident.ValueOffset = ValueOffset;
122
123 // Set the name
124 RtlCopyMemory((PCHAR)((ULONG_PTR)AttributeAddress + NameOffset), Name, NameLength * sizeof(WCHAR));
125
126 // move the attribute-end and file-record-end markers to the end of the file record
127 AttributeAddress = (PNTFS_ATTR_RECORD)((ULONG_PTR)AttributeAddress + AttributeAddress->Length);
128 SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
129
130 return STATUS_SUCCESS;
131}
#define ALIGN_UP_BY(size, align)
#define DPRINT1
Definition: precomp.h:8
struct NTFS_ATTR_RECORD * PNTFS_ATTR_RECORD
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
#define VALUE_OFFSET_ALIGNMENT
Definition: ntfs.h:326
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:320
VOID SetFileRecordEnd(PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttrEnd, ULONG EndMarker)
Definition: mft.c:706
#define Vcb
Definition: cdprocs.h:1415
#define STATUS_SUCCESS
Definition: shellext.h:65
struct NTFS_ATTR_RECORD::@169::@171 Resident
UCHAR Reserved
Definition: ntfs.h:141
ULONG Length
Definition: ntfs.h:127
USHORT NameOffset
Definition: ntfs.h:130
USHORT Instance
Definition: ntfs.h:132
UCHAR NameLength
Definition: ntfs.h:129
ULONG Type
Definition: ntfs.h:126
USHORT NextAttributeNumber
Definition: ntfs.h:260
ULONG BytesInUse
Definition: ntfs.h:257
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
char * PCHAR
Definition: typedefs.h:51
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180

Referenced by DECLARE_INTERFACE_(), CFontsDialog::InitToolbar(), and UpdateIndexAllocation().

◆ AddData()

NTSTATUS AddData ( PFILE_RECORD_HEADER  FileRecord,
PNTFS_ATTR_RECORD  AttributeAddress 
)

Definition at line 160 of file attrib.c.

162{
163 ULONG ResidentHeaderLength = FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.Reserved) + sizeof(UCHAR);
164 ULONG FileRecordEnd = AttributeAddress->Length;
165
166 if (AttributeAddress->Type != AttributeEnd)
167 {
168 DPRINT1("FIXME: Can only add $DATA attribute to the end of a file record.\n");
170 }
171
172 AttributeAddress->Type = AttributeData;
173 AttributeAddress->Length = ResidentHeaderLength;
174 AttributeAddress->Length = ALIGN_UP_BY(AttributeAddress->Length, ATTR_RECORD_ALIGNMENT);
175 AttributeAddress->Resident.ValueLength = 0;
176 AttributeAddress->Resident.ValueOffset = ResidentHeaderLength;
177
178 // for unnamed $DATA attributes, NameOffset equals header length
179 AttributeAddress->NameOffset = ResidentHeaderLength;
180 AttributeAddress->Instance = FileRecord->NextAttributeNumber++;
181
182 // move the attribute-end and file-record-end markers to the end of the file record
183 AttributeAddress = (PNTFS_ATTR_RECORD)((ULONG_PTR)AttributeAddress + AttributeAddress->Length);
184 SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
185
186 return STATUS_SUCCESS;
187}

Referenced by DECLARE_INTERFACE_(), and NtfsCreateFileRecord().

◆ AddFileName()

NTSTATUS AddFileName ( PFILE_RECORD_HEADER  FileRecord,
PNTFS_ATTR_RECORD  AttributeAddress,
PDEVICE_EXTENSION  DeviceExt,
PFILE_OBJECT  FileObject,
BOOLEAN  CaseSensitive,
PULONGLONG  ParentMftIndex 
)

Definition at line 230 of file attrib.c.

236{
237 ULONG ResidentHeaderLength = FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.Reserved) + sizeof(UCHAR);
238 PFILENAME_ATTRIBUTE FileNameAttribute;
239 LARGE_INTEGER SystemTime;
240 ULONG FileRecordEnd = AttributeAddress->Length;
241 ULONGLONG CurrentMFTIndex = NTFS_FILE_ROOT;
242 UNICODE_STRING Current, Remaining, FilenameNoPath;
244 ULONG FirstEntry;
245
246 if (AttributeAddress->Type != AttributeEnd)
247 {
248 DPRINT1("FIXME: Can only add $FILE_NAME attribute to the end of a file record.\n");
250 }
251
252 AttributeAddress->Type = AttributeFileName;
253 AttributeAddress->Instance = FileRecord->NextAttributeNumber++;
254
255 FileNameAttribute = (PFILENAME_ATTRIBUTE)((LONG_PTR)AttributeAddress + ResidentHeaderLength);
256
257 // set timestamps
258 KeQuerySystemTime(&SystemTime);
259 FileNameAttribute->CreationTime = SystemTime.QuadPart;
260 FileNameAttribute->ChangeTime = SystemTime.QuadPart;
261 FileNameAttribute->LastWriteTime = SystemTime.QuadPart;
262 FileNameAttribute->LastAccessTime = SystemTime.QuadPart;
263
264 // Is this a directory?
265 if(FileRecord->Flags & FRH_DIRECTORY)
266 FileNameAttribute->FileAttributes = NTFS_FILE_TYPE_DIRECTORY;
267 else
268 FileNameAttribute->FileAttributes = NTFS_FILE_TYPE_ARCHIVE;
269
270 // we need to extract the filename from the path
271 DPRINT1("Pathname: %wZ\n", &FileObject->FileName);
272
273 FsRtlDissectName(FileObject->FileName, &Current, &Remaining);
274
275 FilenameNoPath.Buffer = Current.Buffer;
276 FilenameNoPath.MaximumLength = FilenameNoPath.Length = Current.Length;
277
278 while (Current.Length != 0)
279 {
280 DPRINT1("Current: %wZ\n", &Current);
281
282 if (Remaining.Length != 0)
283 {
284 FilenameNoPath.Buffer = Remaining.Buffer;
285 FilenameNoPath.Length = FilenameNoPath.MaximumLength = Remaining.Length;
286 }
287
288 FirstEntry = 0;
289 Status = NtfsFindMftRecord(DeviceExt,
290 CurrentMFTIndex,
291 &Current,
292 &FirstEntry,
293 FALSE,
294 CaseSensitive,
295 &CurrentMFTIndex);
296 if (!NT_SUCCESS(Status))
297 break;
298
299 if (Remaining.Length == 0 )
300 {
301 if (Current.Length != 0)
302 {
303 FilenameNoPath.Buffer = Current.Buffer;
304 FilenameNoPath.Length = FilenameNoPath.MaximumLength = Current.Length;
305 }
306 break;
307 }
308
309 FsRtlDissectName(Remaining, &Current, &Remaining);
310 }
311
312 DPRINT1("MFT Index of parent: %I64u\n", CurrentMFTIndex);
313
314 // set reference to parent directory
315 FileNameAttribute->DirectoryFileReferenceNumber = CurrentMFTIndex;
316 *ParentMftIndex = CurrentMFTIndex;
317
318 DPRINT1("SequenceNumber: 0x%02x\n", FileRecord->SequenceNumber);
319
320 // The highest 2 bytes should be the sequence number, unless the parent happens to be root
321 if (CurrentMFTIndex == NTFS_FILE_ROOT)
322 FileNameAttribute->DirectoryFileReferenceNumber |= (ULONGLONG)NTFS_FILE_ROOT << 48;
323 else
324 FileNameAttribute->DirectoryFileReferenceNumber |= (ULONGLONG)FileRecord->SequenceNumber << 48;
325
326 DPRINT1("FileNameAttribute->DirectoryFileReferenceNumber: 0x%016I64x\n", FileNameAttribute->DirectoryFileReferenceNumber);
327
328 FileNameAttribute->NameLength = FilenameNoPath.Length / sizeof(WCHAR);
329 RtlCopyMemory(FileNameAttribute->Name, FilenameNoPath.Buffer, FilenameNoPath.Length);
330
331 // For now, we're emulating the way Windows behaves when 8.3 name generation is disabled
332 // TODO: add DOS Filename as needed
333 if (!CaseSensitive && RtlIsNameLegalDOS8Dot3(&FilenameNoPath, NULL, NULL))
334 FileNameAttribute->NameType = NTFS_FILE_NAME_WIN32_AND_DOS;
335 else
336 FileNameAttribute->NameType = NTFS_FILE_NAME_POSIX;
337
338 FileRecord->LinkCount++;
339
340 AttributeAddress->Length = ResidentHeaderLength +
341 FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + FilenameNoPath.Length;
342 AttributeAddress->Length = ALIGN_UP_BY(AttributeAddress->Length, ATTR_RECORD_ALIGNMENT);
343
344 AttributeAddress->Resident.ValueLength = FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + FilenameNoPath.Length;
345 AttributeAddress->Resident.ValueOffset = ResidentHeaderLength;
346 AttributeAddress->Resident.Flags = RA_INDEXED;
347
348 // move the attribute-end and file-record-end markers to the end of the file record
349 AttributeAddress = (PNTFS_ATTR_RECORD)((ULONG_PTR)AttributeAddress + AttributeAddress->Length);
350 SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
351
352 return Status;
353}
LONG NTSTATUS
Definition: precomp.h:26
#define NTFS_FILE_ROOT
Definition: ntfs.h:28
#define NTFS_FILE_NAME_POSIX
Definition: ntfs.h:63
#define NTFS_FILE_NAME_WIN32_AND_DOS
Definition: ntfs.h:66
static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, PCHAR FileName, ULONGLONG *OutMFTIndex)
Definition: ntfs.c:545
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
struct FILENAME_ATTRIBUTE * PFILENAME_ATTRIBUTE
#define FRH_DIRECTORY
Definition: ntfs.h:268
#define NTFS_FILE_TYPE_DIRECTORY
Definition: ntfs.h:232
#define NTFS_FILE_TYPE_ARCHIVE
Definition: ntfs.h:225
#define RA_INDEXED
Definition: ntfs.h:235
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
Status
Definition: gdiplustypes.h:25
BOOLEAN NTAPI RtlIsNameLegalDOS8Dot3(_In_ PUNICODE_STRING Name, _Inout_opt_ POEM_STRING OemName, _Inout_opt_ PBOOLEAN NameContainsSpaces)
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
VOID NTAPI FsRtlDissectName(IN UNICODE_STRING Name, OUT PUNICODE_STRING FirstPart, OUT PUNICODE_STRING RemainingPart)
Definition: name.c:398
ULONGLONG LastWriteTime
Definition: ntfs.h:363
UCHAR NameLength
Definition: ntfs.h:377
ULONGLONG DirectoryFileReferenceNumber
Definition: ntfs.h:360
UCHAR NameType
Definition: ntfs.h:378
ULONG FileAttributes
Definition: ntfs.h:367
ULONGLONG LastAccessTime
Definition: ntfs.h:364
ULONGLONG CreationTime
Definition: ntfs.h:361
WCHAR Name[1]
Definition: ntfs.h:379
ULONGLONG ChangeTime
Definition: ntfs.h:362
USHORT SequenceNumber
Definition: ntfs.h:253
USHORT Flags
Definition: ntfs.h:256
USHORT LinkCount
Definition: ntfs.h:254
USHORT MaximumLength
Definition: env_spec_w32.h:370
uint64_t ULONGLONG
Definition: typedefs.h:67
LONGLONG QuadPart
Definition: typedefs.h:114
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550

Referenced by NtfsCreateDirectory(), and NtfsCreateFileRecord().

◆ AddFixupArray()

NTSTATUS AddFixupArray ( PDEVICE_EXTENSION  Vcb,
PNTFS_RECORD_HEADER  Record 
)

Definition at line 2603 of file mft.c.

2605{
2606 USHORT *pShortToFixUp;
2607 ULONG ArrayEntryCount = Record->UsaCount - 1;
2608 ULONG Offset = Vcb->NtfsInfo.BytesPerSector - 2;
2609 ULONG i;
2610
2611 PFIXUP_ARRAY fixupArray = (PFIXUP_ARRAY)((UCHAR*)Record + Record->UsaOffset);
2612
2613 DPRINT("AddFixupArray(%p, %p)\n fixupArray->USN: %u, ArrayEntryCount: %u\n", Vcb, Record, fixupArray->USN, ArrayEntryCount);
2614
2615 fixupArray->USN++;
2616
2617 for (i = 0; i < ArrayEntryCount; i++)
2618 {
2619 DPRINT("USN: %u\tOffset: %u\n", fixupArray->USN, Offset);
2620
2621 pShortToFixUp = (USHORT*)((PCHAR)Record + Offset);
2622 fixupArray->Array[i] = *pShortToFixUp;
2623 *pShortToFixUp = fixupArray->USN;
2624 Offset += Vcb->NtfsInfo.BytesPerSector;
2625 }
2626
2627 return STATUS_SUCCESS;
2628}
struct FIXUP_ARRAY * PFIXUP_ARRAY
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
unsigned short USHORT
Definition: pedump.c:61
#define DPRINT
Definition: sndvol32.h:73
USHORT Array[]
Definition: ntfs.h:562
USHORT USN
Definition: ntfs.h:561
_In_ struct _KBUGCHECK_REASON_CALLBACK_RECORD * Record
Definition: ketypes.h:268

Referenced by CreateIndexBufferFromBTreeNode(), UpdateFileRecord(), and UpdateIndexEntryFileNameSize().

◆ AddIndexAllocation()

NTSTATUS AddIndexAllocation ( PNTFS_VCB  Vcb,
PFILE_RECORD_HEADER  FileRecord,
PNTFS_ATTR_RECORD  AttributeAddress,
PCWSTR  Name,
USHORT  NameLength 
)

Definition at line 388 of file attrib.c.

393{
394 ULONG RecordLength;
395 ULONG FileRecordEnd;
396 ULONG NameOffset;
397 ULONG DataRunOffset;
398 ULONG BytesAvailable;
399
400 if (AttributeAddress->Type != AttributeEnd)
401 {
402 DPRINT1("FIXME: Can only add $INDEX_ALLOCATION attribute to the end of a file record.\n");
404 }
405
406 // Calculate the name offset
407 NameOffset = FIELD_OFFSET(NTFS_ATTR_RECORD, NonResident.CompressedSize);
408
409 // Calculate the offset to the first data run
410 DataRunOffset = (sizeof(WCHAR) * NameLength) + NameOffset;
411 // The data run offset must be aligned to a 4-byte boundary
412 DataRunOffset = ALIGN_UP_BY(DataRunOffset, DATA_RUN_ALIGNMENT);
413
414 // Calculate the length of the new attribute; the empty data run will consist of a single byte
415 RecordLength = DataRunOffset + 1;
416
417 // The size of the attribute itself must be aligned to an 8 - byte boundary
418 RecordLength = ALIGN_UP_BY(RecordLength, ATTR_RECORD_ALIGNMENT);
419
420 // Back up the last 4-bytes of the file record (even though this value doesn't matter)
421 FileRecordEnd = AttributeAddress->Length;
422
423 // Make sure the file record can contain the new attribute
424 BytesAvailable = Vcb->NtfsInfo.BytesPerFileRecord - FileRecord->BytesInUse;
425 if (BytesAvailable < RecordLength)
426 {
427 DPRINT1("FIXME: Not enough room in file record for index allocation attribute!\n");
429 }
430
431 // Set fields of attribute header
432 RtlZeroMemory(AttributeAddress, RecordLength);
433
434 AttributeAddress->Type = AttributeIndexAllocation;
435 AttributeAddress->Length = RecordLength;
436 AttributeAddress->IsNonResident = TRUE;
437 AttributeAddress->NameLength = NameLength;
438 AttributeAddress->NameOffset = NameOffset;
439 AttributeAddress->Instance = FileRecord->NextAttributeNumber++;
440
441 AttributeAddress->NonResident.MappingPairsOffset = DataRunOffset;
442 AttributeAddress->NonResident.HighestVCN = (LONGLONG)-1;
443
444 // Set the name
445 RtlCopyMemory((PCHAR)((ULONG_PTR)AttributeAddress + NameOffset), Name, NameLength * sizeof(WCHAR));
446
447 // move the attribute-end and file-record-end markers to the end of the file record
448 AttributeAddress = (PNTFS_ATTR_RECORD)((ULONG_PTR)AttributeAddress + AttributeAddress->Length);
449 SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
450
451 return STATUS_SUCCESS;
452}
#define TRUE
Definition: types.h:120
#define DATA_RUN_ALIGNMENT
Definition: ntfs.h:323
LONGLONG CompressedSize
Definition: ntfs.h:154
UCHAR IsNonResident
Definition: ntfs.h:128
struct NTFS_ATTR_RECORD::@169::@172 NonResident
int64_t LONGLONG
Definition: typedefs.h:68

Referenced by UpdateIndexAllocation().

◆ AddIndexRoot()

NTSTATUS AddIndexRoot ( PNTFS_VCB  Vcb,
PFILE_RECORD_HEADER  FileRecord,
PNTFS_ATTR_RECORD  AttributeAddress,
PINDEX_ROOT_ATTRIBUTE  NewIndexRoot,
ULONG  RootLength,
PCWSTR  Name,
USHORT  NameLength 
)

Definition at line 495 of file attrib.c.

502{
503 ULONG AttributeLength;
504 // Calculate the header length
505 ULONG ResidentHeaderLength = FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.Reserved) + sizeof(UCHAR);
506 // Back up the file record's final ULONG (even though it doesn't matter)
507 ULONG FileRecordEnd = AttributeAddress->Length;
508 ULONG NameOffset;
509 ULONG ValueOffset;
510 ULONG BytesAvailable;
511
512 if (AttributeAddress->Type != AttributeEnd)
513 {
514 DPRINT1("FIXME: Can only add $DATA attribute to the end of a file record.\n");
516 }
517
518 NameOffset = ResidentHeaderLength;
519
520 // Calculate ValueOffset, which will be aligned to a 4-byte boundary
521 ValueOffset = ALIGN_UP_BY(NameOffset + (sizeof(WCHAR) * NameLength), VALUE_OFFSET_ALIGNMENT);
522
523 // Calculate length of attribute
524 AttributeLength = ValueOffset + RootLength;
525 AttributeLength = ALIGN_UP_BY(AttributeLength, ATTR_RECORD_ALIGNMENT);
526
527 // Make sure the file record is large enough for the new attribute
528 BytesAvailable = Vcb->NtfsInfo.BytesPerFileRecord - FileRecord->BytesInUse;
529 if (BytesAvailable < AttributeLength)
530 {
531 DPRINT1("FIXME: Not enough room in file record for index allocation attribute!\n");
533 }
534
535 // Set Attribute fields
536 RtlZeroMemory(AttributeAddress, AttributeLength);
537
538 AttributeAddress->Type = AttributeIndexRoot;
539 AttributeAddress->Length = AttributeLength;
540 AttributeAddress->NameLength = NameLength;
541 AttributeAddress->NameOffset = NameOffset;
542 AttributeAddress->Instance = FileRecord->NextAttributeNumber++;
543
544 AttributeAddress->Resident.ValueLength = RootLength;
545 AttributeAddress->Resident.ValueOffset = ValueOffset;
546
547 // Set the name
548 RtlCopyMemory((PCHAR)((ULONG_PTR)AttributeAddress + NameOffset), Name, NameLength * sizeof(WCHAR));
549
550 // Copy the index root attribute
551 RtlCopyMemory((PCHAR)((ULONG_PTR)AttributeAddress + ValueOffset), NewIndexRoot, RootLength);
552
553 // move the attribute-end and file-record-end markers to the end of the file record
554 AttributeAddress = (PNTFS_ATTR_RECORD)((ULONG_PTR)AttributeAddress + AttributeAddress->Length);
555 SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
556
557 return STATUS_SUCCESS;
558}

Referenced by NtfsCreateDirectory().

◆ AddNewMftEntry()

NTSTATUS AddNewMftEntry ( PFILE_RECORD_HEADER  FileRecord,
PDEVICE_EXTENSION  DeviceExt,
PULONGLONG  DestinationIndex,
BOOLEAN  CanWait 
)

Definition at line 2022 of file mft.c.

2026{
2028 ULONGLONG MftIndex;
2030 ULONGLONG BitmapDataSize;
2031 ULONGLONG AttrBytesRead;
2034 ULONG LengthWritten;
2035 PNTFS_ATTR_CONTEXT BitmapContext;
2036 LARGE_INTEGER BitmapBits;
2037 UCHAR SystemReservedBits;
2038
2039 DPRINT1("AddNewMftEntry(%p, %p, %p, %s)\n", FileRecord, DeviceExt, DestinationIndex, CanWait ? "TRUE" : "FALSE");
2040
2041 // First, we have to read the mft's $Bitmap attribute
2042
2043 // Find the attribute
2044 Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
2045 if (!NT_SUCCESS(Status))
2046 {
2047 DPRINT1("ERROR: Couldn't find $Bitmap attribute of master file table!\n");
2048 return Status;
2049 }
2050
2051 // Get size of bitmap
2052 BitmapDataSize = AttributeDataLength(BitmapContext->pRecord);
2053
2054 // RtlInitializeBitmap wants a ULONG-aligned pointer, and wants the memory passed to it to be a ULONG-multiple
2055 // Allocate a buffer for the $Bitmap attribute plus enough to ensure we can get a ULONG-aligned pointer
2056 BitmapBuffer = ExAllocatePoolWithTag(NonPagedPool, BitmapDataSize + sizeof(ULONG), TAG_NTFS);
2057 if (!BitmapBuffer)
2058 {
2059 ReleaseAttributeContext(BitmapContext);
2061 }
2062 RtlZeroMemory(BitmapBuffer, BitmapDataSize + sizeof(ULONG));
2063
2064 // Get a ULONG-aligned pointer for the bitmap itself
2066
2067 // read $Bitmap attribute
2068 AttrBytesRead = ReadAttribute(DeviceExt, BitmapContext, 0, (PCHAR)BitmapData, BitmapDataSize);
2069
2070 if (AttrBytesRead != BitmapDataSize)
2071 {
2072 DPRINT1("ERROR: Unable to read $Bitmap attribute of master file table!\n");
2074 ReleaseAttributeContext(BitmapContext);
2076 }
2077
2078 // We need to backup the bits for records 0x10 - 0x17 (3rd byte of bitmap) and mark these records
2079 // as in-use so we don't assign files to those indices. They're reserved for the system (e.g. ChkDsk).
2080 SystemReservedBits = BitmapData[2];
2081 BitmapData[2] = 0xff;
2082
2083 // Calculate bit count
2084 BitmapBits.QuadPart = AttributeDataLength(DeviceExt->MFTContext->pRecord) /
2085 DeviceExt->NtfsInfo.BytesPerFileRecord;
2086 if (BitmapBits.HighPart != 0)
2087 {
2088 DPRINT1("\tFIXME: bitmap sizes beyond 32bits are not yet supported! (Your NTFS volume is too large)\n");
2091 ReleaseAttributeContext(BitmapContext);
2093 }
2094
2095 // convert buffer into bitmap
2097
2098 // set next available bit, preferrably after 23rd bit
2099 MftIndex = RtlFindClearBitsAndSet(&Bitmap, 1, 24);
2100 if ((LONG)MftIndex == -1)
2101 {
2102 DPRINT1("Couldn't find free space in MFT for file record, increasing MFT size.\n");
2103
2105 ReleaseAttributeContext(BitmapContext);
2106
2107 // Couldn't find a free record in the MFT, add some blank records and try again
2108 Status = IncreaseMftSize(DeviceExt, CanWait);
2109 if (!NT_SUCCESS(Status))
2110 {
2111 DPRINT1("ERROR: Couldn't find space in MFT for file or increase MFT size!\n");
2112 return Status;
2113 }
2114
2115 return AddNewMftEntry(FileRecord, DeviceExt, DestinationIndex, CanWait);
2116 }
2117
2118 DPRINT1("Creating file record at MFT index: %I64u\n", MftIndex);
2119
2120 // update file record with index
2121 FileRecord->MFTRecordNumber = MftIndex;
2122
2123 // [BitmapData should have been updated via RtlFindClearBitsAndSet()]
2124
2125 // Restore the system reserved bits
2126 BitmapData[2] = SystemReservedBits;
2127
2128 // write the bitmap back to the MFT's $Bitmap attribute
2129 Status = WriteAttribute(DeviceExt, BitmapContext, 0, BitmapData, BitmapDataSize, &LengthWritten, FileRecord);
2130 if (!NT_SUCCESS(Status))
2131 {
2132 DPRINT1("ERROR encountered when writing $Bitmap attribute!\n");
2134 ReleaseAttributeContext(BitmapContext);
2135 return Status;
2136 }
2137
2138 // update the file record (write it to disk)
2139 Status = UpdateFileRecord(DeviceExt, MftIndex, FileRecord);
2140
2141 if (!NT_SUCCESS(Status))
2142 {
2143 DPRINT1("ERROR: Unable to write file record!\n");
2145 ReleaseAttributeContext(BitmapContext);
2146 return Status;
2147 }
2148
2149 *DestinationIndex = MftIndex;
2150
2152 ReleaseAttributeContext(BitmapContext);
2153
2154 return Status;
2155}
#define RtlInitializeBitMap
Definition: dbgbitmap.h:326
#define RtlFindClearBitsAndSet
Definition: dbgbitmap.h:333
PNTFS_GLOBAL_DATA NtfsGlobalData
Definition: ntfs.c:36
#define TAG_NTFS
Definition: ntfs.h:12
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define NonPagedPool
Definition: env_spec_w32.h:307
static ULONG BitmapBuffer[(XMS_BLOCKS+31)/32]
Definition: himem.c:86
NTSTATUS UpdateFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1931
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
NTSTATUS FindAttribute(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER MftRecord, ULONG Type, PCWSTR Name, ULONG NameLength, PNTFS_ATTR_CONTEXT *AttrCtx, PULONG Offset)
Definition: mft.c:131
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
NTSTATUS WriteAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, const PUCHAR Buffer, ULONG Length, PULONG RealLengthWritten, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1315
NTSTATUS IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
Definition: mft.c:293
NTSTATUS AddNewMftEntry(PFILE_RECORD_HEADER FileRecord, PDEVICE_EXTENSION DeviceExt, PULONGLONG DestinationIndex, BOOLEAN CanWait)
Definition: mft.c:2022
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
#define L(x)
Definition: ntvdm.h:50
long LONG
Definition: pedump.c:60
BOOLEAN EnableWriteSupport
Definition: ntfs.h:155
ULONG MFTRecordNumber
Definition: ntfs.h:262
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char * PUCHAR
Definition: typedefs.h:53
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
ULONG LowPart
Definition: typedefs.h:106

Referenced by AddNewMftEntry(), NtfsCreateDirectory(), and NtfsCreateFileRecord().

◆ AddRun()

NTSTATUS AddRun ( PNTFS_VCB  Vcb,
PNTFS_ATTR_CONTEXT  AttrContext,
ULONG  AttrOffset,
PFILE_RECORD_HEADER  FileRecord,
ULONGLONG  NextAssignedCluster,
ULONG  RunLength 
)

Definition at line 599 of file attrib.c.

605{
607 int DataRunMaxLength;
608 PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
609 ULONG NextAttributeOffset = AttrOffset + AttrContext->pRecord->Length;
610 ULONGLONG NextVBN = 0;
611
612 PUCHAR RunBuffer;
613 ULONG RunBufferSize;
614
615 if (!AttrContext->pRecord->IsNonResident)
617
618 if (AttrContext->pRecord->NonResident.AllocatedSize != 0)
619 NextVBN = AttrContext->pRecord->NonResident.HighestVCN + 1;
620
621 // Add newly-assigned clusters to mcb
623 {
624 if (!FsRtlAddLargeMcbEntry(&AttrContext->DataRunsMCB,
625 NextVBN,
626 NextAssignedCluster,
627 RunLength))
628 {
630 }
631 }
633 {
634 DPRINT1("Failed to add LargeMcb Entry!\n");
636 }
637 _SEH2_END;
638
639 RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
640 if (!RunBuffer)
641 {
642 DPRINT1("ERROR: Couldn't allocate memory for data runs!\n");
644 }
645
646 // Convert the map control block back to encoded data runs
647 ConvertLargeMCBToDataRuns(&AttrContext->DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferSize);
648
649 // Get the amount of free space between the start of the of the first data run and the attribute end
650 DataRunMaxLength = AttrContext->pRecord->Length - AttrContext->pRecord->NonResident.MappingPairsOffset;
651
652 // Do we need to extend the attribute (or convert to attribute list)?
653 if (DataRunMaxLength < RunBufferSize)
654 {
655 PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
656 PNTFS_ATTR_RECORD NewRecord;
657
658 // Add free space at the end of the file record to DataRunMaxLength
659 DataRunMaxLength += Vcb->NtfsInfo.BytesPerFileRecord - FileRecord->BytesInUse;
660
661 // Can we resize the attribute?
662 if (DataRunMaxLength < RunBufferSize)
663 {
664 DPRINT1("FIXME: Need to create attribute list! Max Data Run Length available: %d, RunBufferSize: %d\n", DataRunMaxLength, RunBufferSize);
665 ExFreePoolWithTag(RunBuffer, TAG_NTFS);
667 }
668
669 // Are there more attributes after the one we're resizing?
670 if (NextAttribute->Type != AttributeEnd)
671 {
672 PNTFS_ATTR_RECORD FinalAttribute;
673
674 // Calculate where to move the trailing attributes
675 ULONG_PTR MoveTo = (ULONG_PTR)DestinationAttribute + AttrContext->pRecord->NonResident.MappingPairsOffset + RunBufferSize;
676 MoveTo = ALIGN_UP_BY(MoveTo, ATTR_RECORD_ALIGNMENT);
677
678 DPRINT1("Moving attribute(s) after this one starting with type 0x%lx\n", NextAttribute->Type);
679
680 // Move the trailing attributes; FinalAttribute will point to the end marker
681 FinalAttribute = MoveAttributes(Vcb, NextAttribute, NextAttributeOffset, MoveTo);
682
683 // set the file record end
684 SetFileRecordEnd(FileRecord, FinalAttribute, FILE_RECORD_END);
685 }
686
687 // calculate position of end markers
688 NextAttributeOffset = AttrOffset + AttrContext->pRecord->NonResident.MappingPairsOffset + RunBufferSize;
689 NextAttributeOffset = ALIGN_UP_BY(NextAttributeOffset, ATTR_RECORD_ALIGNMENT);
690
691 // Update the length of the destination attribute
692 DestinationAttribute->Length = NextAttributeOffset - AttrOffset;
693
694 // Create a new copy of the attribute record
695 NewRecord = ExAllocatePoolWithTag(NonPagedPool, DestinationAttribute->Length, TAG_NTFS);
696 RtlCopyMemory(NewRecord, AttrContext->pRecord, AttrContext->pRecord->Length);
697 NewRecord->Length = DestinationAttribute->Length;
698
699 // Free the old copy of the attribute record, which won't be large enough
700 ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS);
701
702 // Set the attribute context's record to the new copy
703 AttrContext->pRecord = NewRecord;
704
705 // if NextAttribute is the AttributeEnd marker
706 if (NextAttribute->Type == AttributeEnd)
707 {
708 // End the file record
709 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
710 SetFileRecordEnd(FileRecord, NextAttribute, FILE_RECORD_END);
711 }
712 }
713
714 // Update HighestVCN
715 DestinationAttribute->NonResident.HighestVCN =
716 AttrContext->pRecord->NonResident.HighestVCN = max(NextVBN - 1 + RunLength,
717 AttrContext->pRecord->NonResident.HighestVCN);
718
719 // Write data runs to destination attribute
720 RtlCopyMemory((PVOID)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset),
721 RunBuffer,
722 RunBufferSize);
723
724 // Update the attribute record in the attribute context
725 RtlCopyMemory((PVOID)((ULONG_PTR)AttrContext->pRecord + AttrContext->pRecord->NonResident.MappingPairsOffset),
726 RunBuffer,
727 RunBufferSize);
728
729 // Update the file record
730 Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord);
731
732 ExFreePoolWithTag(RunBuffer, TAG_NTFS);
733
734 NtfsDumpDataRuns((PUCHAR)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), 0);
735
736 return Status;
737}
VOID NtfsDumpDataRuns(PVOID StartOfRun, ULONGLONG CurrentLCN)
Definition: attrib.c:1755
NTSTATUS ConvertLargeMCBToDataRuns(PLARGE_MCB DataRunsMCB, PUCHAR RunBuffer, ULONG MaxBufferSize, PULONG UsedBufferSize)
Definition: attrib.c:896
#define FILE_RECORD_END
Definition: ntfs.h:182
#define ULONG_PTR
Definition: config.h:101
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
BOOLEAN NTAPI FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb, IN LONGLONG Vbn, IN LONGLONG Lbn, IN LONGLONG SectorCount)
Definition: largemcb.c:288
PNTFS_ATTR_RECORD MoveAttributes(PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_RECORD FirstAttributeToMove, ULONG FirstAttributeOffset, ULONG_PTR MoveTo)
Definition: mft.c:512
#define ExRaiseStatus
Definition: ntoskrnl.h:114
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:66
#define _SEH2_END
Definition: pseh2_64.h:155
#define _SEH2_TRY
Definition: pseh2_64.h:55
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:168
#define max(a, b)
Definition: svc.c:63
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132

Referenced by SetNonResidentAttributeDataLength().

◆ AddStandardInformation()

NTSTATUS AddStandardInformation ( PFILE_RECORD_HEADER  FileRecord,
PNTFS_ATTR_RECORD  AttributeAddress 
)

Definition at line 766 of file attrib.c.

768{
769 ULONG ResidentHeaderLength = FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.Reserved) + sizeof(UCHAR);
770 PSTANDARD_INFORMATION StandardInfo = (PSTANDARD_INFORMATION)((LONG_PTR)AttributeAddress + ResidentHeaderLength);
771 LARGE_INTEGER SystemTime;
772 ULONG FileRecordEnd = AttributeAddress->Length;
773
774 if (AttributeAddress->Type != AttributeEnd)
775 {
776 DPRINT1("FIXME: Can only add $STANDARD_INFORMATION attribute to the end of a file record.\n");
778 }
779
780 AttributeAddress->Type = AttributeStandardInformation;
781 AttributeAddress->Length = sizeof(STANDARD_INFORMATION) + ResidentHeaderLength;
782 AttributeAddress->Length = ALIGN_UP_BY(AttributeAddress->Length, ATTR_RECORD_ALIGNMENT);
783 AttributeAddress->Resident.ValueLength = sizeof(STANDARD_INFORMATION);
784 AttributeAddress->Resident.ValueOffset = ResidentHeaderLength;
785 AttributeAddress->Instance = FileRecord->NextAttributeNumber++;
786
787 // set dates and times
788 KeQuerySystemTime(&SystemTime);
789 StandardInfo->CreationTime = SystemTime.QuadPart;
790 StandardInfo->ChangeTime = SystemTime.QuadPart;
791 StandardInfo->LastWriteTime = SystemTime.QuadPart;
792 StandardInfo->LastAccessTime = SystemTime.QuadPart;
794
795 // move the attribute-end and file-record-end markers to the end of the file record
796 AttributeAddress = (PNTFS_ATTR_RECORD)((ULONG_PTR)AttributeAddress + AttributeAddress->Length);
797 SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
798
799 return STATUS_SUCCESS;
800}
struct STANDARD_INFORMATION * PSTANDARD_INFORMATION
ULONGLONG LastAccessTime
Definition: ntfs.h:333
ULONGLONG ChangeTime
Definition: ntfs.h:331
ULONGLONG LastWriteTime
Definition: ntfs.h:332
ULONG FileAttribute
Definition: ntfs.h:334
ULONGLONG CreationTime
Definition: ntfs.h:330

Referenced by NtfsCreateDirectory(), and NtfsCreateFileRecord().

◆ AttributeAllocatedLength()

ULONGLONG AttributeAllocatedLength ( PNTFS_ATTR_RECORD  AttrRecord)

Definition at line 249 of file mft.c.

250{
251 if (AttrRecord->IsNonResident)
252 return AttrRecord->NonResident.AllocatedSize;
253 else
254 return ALIGN_UP_BY(AttrRecord->Resident.ValueLength, ATTR_RECORD_ALIGNMENT);
255}

Referenced by NtfsGetFileSize(), NtfsGetStreamInformation(), NtfsReadFile(), NtfsSetEndOfFile(), and NtfsWriteFile().

◆ AttributeDataLength()

◆ CompareFileName()

BOOLEAN CompareFileName ( PUNICODE_STRING  FileName,
PINDEX_ENTRY_ATTRIBUTE  IndexEntry,
BOOLEAN  DirSearch,
BOOLEAN  CaseSensitive 
)

Definition at line 2650 of file mft.c.

2654{
2655 BOOLEAN Ret, Alloc = FALSE;
2656 UNICODE_STRING EntryName;
2657
2658 EntryName.Buffer = IndexEntry->FileName.Name;
2659 EntryName.Length =
2660 EntryName.MaximumLength = IndexEntry->FileName.NameLength * sizeof(WCHAR);
2661
2662 if (DirSearch)
2663 {
2664 UNICODE_STRING IntFileName;
2665 if (!CaseSensitive)
2666 {
2668 Alloc = TRUE;
2669 }
2670 else
2671 {
2672 IntFileName = *FileName;
2673 }
2674
2675 Ret = FsRtlIsNameInExpression(&IntFileName, &EntryName, !CaseSensitive, NULL);
2676
2677 if (Alloc)
2678 {
2679 RtlFreeUnicodeString(&IntFileName);
2680 }
2681
2682 return Ret;
2683 }
2684 else
2685 {
2686 return (RtlCompareUnicodeString(FileName, &EntryName, !CaseSensitive) == 0);
2687 }
2688}
unsigned char BOOLEAN
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
struct _FileName FileName
Definition: fatprocs.h:897
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
BOOLEAN NTAPI FsRtlIsNameInExpression(IN PUNICODE_STRING Expression, IN PUNICODE_STRING Name, IN BOOLEAN IgnoreCase, IN PWCHAR UpcaseTable OPTIONAL)
Definition: name.c:514
FILENAME_ATTRIBUTE FileName
Definition: ntfs.h:427
#define NT_VERIFY(exp)
Definition: rtlfuncs.h:3304

Referenced by BrowseIndexEntries(), BrowseSubNodeIndexEntries(), and UpdateIndexEntryFileNameSize().

◆ CompareTreeKeys()

LONG CompareTreeKeys ( PB_TREE_KEY  Key1,
PB_TREE_KEY  Key2,
BOOLEAN  CaseSensitive 
)

Definition at line 417 of file btree.c.

418{
419 UNICODE_STRING Key1Name, Key2Name;
420 LONG Comparison;
421
422 // Key1 must not be the final key (AKA the dummy key)
424
425 // If Key2 is the "dummy key", key 1 will always come first
426 if (Key2->NextKey == NULL)
427 return -1;
428
429 Key1Name.Buffer = Key1->IndexEntry->FileName.Name;
430 Key1Name.Length = Key1Name.MaximumLength
431 = Key1->IndexEntry->FileName.NameLength * sizeof(WCHAR);
432
433 Key2Name.Buffer = Key2->IndexEntry->FileName.Name;
434 Key2Name.Length = Key2Name.MaximumLength
435 = Key2->IndexEntry->FileName.NameLength * sizeof(WCHAR);
436
437 // Are the two keys the same length?
438 if (Key1Name.Length == Key2Name.Length)
439 return RtlCompareUnicodeString(&Key1Name, &Key2Name, !CaseSensitive);
440
441 // Is Key1 shorter?
442 if (Key1Name.Length < Key2Name.Length)
443 {
444 // Truncate KeyName2 to be the same length as KeyName1
445 Key2Name.Length = Key1Name.Length;
446
447 // Compare the names of the same length
448 Comparison = RtlCompareUnicodeString(&Key1Name, &Key2Name, !CaseSensitive);
449
450 // If the truncated names are the same length, the shorter one comes first
451 if (Comparison == 0)
452 return -1;
453 }
454 else
455 {
456 // Key2 is shorter
457 // Truncate KeyName1 to be the same length as KeyName2
458 Key1Name.Length = Key2Name.Length;
459
460 // Compare the names of the same length
461 Comparison = RtlCompareUnicodeString(&Key1Name, &Key2Name, !CaseSensitive);
462
463 // If the truncated names are the same length, the shorter one comes first
464 if (Comparison == 0)
465 return 1;
466 }
467
468 return Comparison;
469}
#define NTFS_INDEX_ENTRY_END
Definition: ntfs.h:61
#define ASSERT(a)
Definition: mode.c:44
USHORT Flags
Definition: ntfs.h:425
struct _B_TREE_KEY * NextKey
Definition: ntfs.h:436
PINDEX_ENTRY_ATTRIBUTE IndexEntry
Definition: ntfs.h:438

Referenced by NtfsInsertKey().

◆ ConvertDataRunsToLargeMCB()

NTSTATUS ConvertDataRunsToLargeMCB ( PUCHAR  DataRun,
PLARGE_MCB  DataRunsMCB,
PULONGLONG  pNextVBN 
)

Definition at line 825 of file attrib.c.

828{
829 LONGLONG DataRunOffset;
830 ULONGLONG DataRunLength;
831 LONGLONG DataRunStartLCN;
832 ULONGLONG LastLCN = 0;
833
834 // Initialize the MCB, potentially catch an exception
835 _SEH2_TRY{
839 } _SEH2_END;
840
841 while (*DataRun != 0)
842 {
843 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
844
845 if (DataRunOffset != -1)
846 {
847 // Normal data run.
848 DataRunStartLCN = LastLCN + DataRunOffset;
849 LastLCN = DataRunStartLCN;
850
851 _SEH2_TRY{
852 if (!FsRtlAddLargeMcbEntry(DataRunsMCB,
853 *pNextVBN,
854 DataRunStartLCN,
855 DataRunLength))
856 {
858 }
860 FsRtlUninitializeLargeMcb(DataRunsMCB);
862 } _SEH2_END;
863
864 }
865
866 *pNextVBN += DataRunLength;
867 }
868
869 return STATUS_SUCCESS;
870}
PUCHAR DecodeRun(PUCHAR DataRun, LONGLONG *DataRunOffset, ULONGLONG *DataRunLength)
Definition: attrib.c:966
VOID NTAPI FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:1096
VOID NTAPI FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb, IN POOL_TYPE PoolType)
Definition: largemcb.c:451

Referenced by PrepareAttributeContext().

◆ ConvertLargeMCBToDataRuns()

NTSTATUS ConvertLargeMCBToDataRuns ( PLARGE_MCB  DataRunsMCB,
PUCHAR  RunBuffer,
ULONG  MaxBufferSize,
PULONG  UsedBufferSize 
)

Definition at line 896 of file attrib.c.

900{
902 ULONG RunBufferOffset = 0;
903 LONGLONG DataRunOffset;
904 ULONGLONG LastLCN = 0;
906 ULONG i;
907
908
909 DPRINT("\t[Vbn, Lbn, Count]\n");
910
911 // convert each mcb entry to a data run
912 for (i = 0; FsRtlGetNextLargeMcbEntry(DataRunsMCB, i, &Vbn, &Lbn, &Count); i++)
913 {
914 UCHAR DataRunOffsetSize = 0;
915 UCHAR DataRunLengthSize = 0;
916 UCHAR ControlByte = 0;
917
918 // [vbn, lbn, count]
919 DPRINT("\t[%I64d, %I64d,%I64d]\n", Vbn, Lbn, Count);
920
921 // TODO: check for holes and convert to sparse runs
922 DataRunOffset = Lbn - LastLCN;
923 LastLCN = Lbn;
924
925 // now we need to determine how to represent DataRunOffset with the minimum number of bytes
926 DPRINT("Determining how many bytes needed to represent %I64x\n", DataRunOffset);
927 DataRunOffsetSize = GetPackedByteCount(DataRunOffset, TRUE);
928 DPRINT("%d bytes needed.\n", DataRunOffsetSize);
929
930 // determine how to represent DataRunLengthSize with the minimum number of bytes
931 DPRINT("Determining how many bytes needed to represent %I64x\n", Count);
932 DataRunLengthSize = GetPackedByteCount(Count, TRUE);
933 DPRINT("%d bytes needed.\n", DataRunLengthSize);
934
935 // ensure the next data run + end marker would be <= Max buffer size
936 if (RunBufferOffset + 2 + DataRunLengthSize + DataRunOffsetSize > MaxBufferSize)
937 {
939 DPRINT1("FIXME: Ran out of room in buffer for data runs!\n");
940 break;
941 }
942
943 // pack and copy the control byte
944 ControlByte = (DataRunOffsetSize << 4) + DataRunLengthSize;
945 RunBuffer[RunBufferOffset++] = ControlByte;
946
947 // copy DataRunLength
948 RtlCopyMemory(RunBuffer + RunBufferOffset, &Count, DataRunLengthSize);
949 RunBufferOffset += DataRunLengthSize;
950
951 // copy DataRunOffset
952 RtlCopyMemory(RunBuffer + RunBufferOffset, &DataRunOffset, DataRunOffsetSize);
953 RunBufferOffset += DataRunOffsetSize;
954 }
955
956 // End of data runs
957 RunBuffer[RunBufferOffset++] = 0;
958
959 *UsedBufferSize = RunBufferOffset;
960 DPRINT("New Size of DataRuns: %ld\n", *UsedBufferSize);
961
962 return Status;
963}
UCHAR GetPackedByteCount(LONGLONG NumberToPack, BOOLEAN IsSigned)
Definition: attrib.c:1846
_In_ LONGLONG Vbn
Definition: fsrtlfuncs.h:470
_Must_inspect_result_ _In_ LONGLONG _In_ LONGLONG Lbn
Definition: fsrtlfuncs.h:480
BOOLEAN NTAPI FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb, IN ULONG RunIndex, OUT PLONGLONG Vbn, OUT PLONGLONG Lbn, OUT PLONGLONG SectorCount)
Definition: largemcb.c:392
int Count
Definition: noreturn.cpp:7
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69

Referenced by AddRun(), FreeClusters(), ReadAttribute(), and WriteAttribute().

◆ CreateBTreeFromIndex()

NTSTATUS CreateBTreeFromIndex ( PDEVICE_EXTENSION  Vcb,
PFILE_RECORD_HEADER  FileRecordWithIndex,
PNTFS_ATTR_CONTEXT  IndexRootContext,
PINDEX_ROOT_ATTRIBUTE  IndexRoot,
PB_TREE NewTree 
)

Definition at line 682 of file btree.c.

688{
689 PINDEX_ENTRY_ATTRIBUTE CurrentNodeEntry;
693 ULONG CurrentOffset = IndexRoot->Header.FirstEntryOffset;
694 PNTFS_ATTR_CONTEXT IndexAllocationContext = NULL;
696
697 DPRINT("CreateBTreeFromIndex(%p, %p)\n", IndexRoot, NewTree);
698
699 if (!Tree || !RootNode || !CurrentKey)
700 {
701 DPRINT1("Couldn't allocate enough memory for B-Tree!\n");
702 if (Tree)
704 if (CurrentKey)
705 ExFreePoolWithTag(CurrentKey, TAG_NTFS);
706 if (RootNode)
709 }
710
711 RtlZeroMemory(Tree, sizeof(B_TREE));
713 RtlZeroMemory(CurrentKey, sizeof(B_TREE_KEY));
714
715 // See if the file record has an attribute allocation
717 FileRecordWithIndex,
719 L"$I30",
720 4,
721 &IndexAllocationContext,
722 NULL);
723 if (!NT_SUCCESS(Status))
724 IndexAllocationContext = NULL;
725
726 // Setup the Tree
727 RootNode->FirstKey = CurrentKey;
728 Tree->RootNode = RootNode;
729
730 // Make sure we won't try reading past the attribute-end
731 if (FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header) + IndexRoot->Header.TotalSizeOfEntries > IndexRootContext->pRecord->Resident.ValueLength)
732 {
733 DPRINT1("Filesystem corruption detected!\n");
736 goto Cleanup;
737 }
738
739 // Start at the first node entry
740 CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexRoot
742 + IndexRoot->Header.FirstEntryOffset);
743
744 // Create a key for each entry in the node
745 while (CurrentOffset < IndexRoot->Header.TotalSizeOfEntries)
746 {
747 // Allocate memory for the current entry
748 CurrentKey->IndexEntry = ExAllocatePoolWithTag(NonPagedPool, CurrentNodeEntry->Length, TAG_NTFS);
749 if (!CurrentKey->IndexEntry)
750 {
751 DPRINT1("ERROR: Couldn't allocate memory for next key!\n");
754 goto Cleanup;
755 }
756
757 RootNode->KeyCount++;
758
759 // If this isn't the last entry
760 if (!(CurrentNodeEntry->Flags & NTFS_INDEX_ENTRY_END))
761 {
762 // Create the next key
764 if (!NextKey)
765 {
766 DPRINT1("ERROR: Couldn't allocate memory for next key!\n");
769 goto Cleanup;
770 }
771
772 RtlZeroMemory(NextKey, sizeof(B_TREE_KEY));
773
774 // Add NextKey to the end of the list
775 CurrentKey->NextKey = NextKey;
776
777 // Copy the current entry to its key
778 RtlCopyMemory(CurrentKey->IndexEntry, CurrentNodeEntry, CurrentNodeEntry->Length);
779
780 // Does this key have a sub-node?
781 if (CurrentKey->IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
782 {
783 // Create the child node
785 IndexRoot,
786 IndexAllocationContext,
787 CurrentKey->IndexEntry);
788 if (!CurrentKey->LesserChild)
789 {
790 DPRINT1("ERROR: Couldn't create child node!\n");
793 goto Cleanup;
794 }
795 }
796
797 // Advance to the next entry
798 CurrentOffset += CurrentNodeEntry->Length;
799 CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)CurrentNodeEntry + CurrentNodeEntry->Length);
800 CurrentKey = NextKey;
801 }
802 else
803 {
804 // Copy the final entry to its key
805 RtlCopyMemory(CurrentKey->IndexEntry, CurrentNodeEntry, CurrentNodeEntry->Length);
806 CurrentKey->NextKey = NULL;
807
808 // Does this key have a sub-node?
809 if (CurrentKey->IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
810 {
811 // Create the child node
813 IndexRoot,
814 IndexAllocationContext,
815 CurrentKey->IndexEntry);
816 if (!CurrentKey->LesserChild)
817 {
818 DPRINT1("ERROR: Couldn't create child node!\n");
821 goto Cleanup;
822 }
823 }
824
825 break;
826 }
827 }
828
829 *NewTree = Tree;
831
832Cleanup:
833 if (IndexAllocationContext)
834 ReleaseAttributeContext(IndexAllocationContext);
835
836 return Status;
837}
CRegistryTree Tree
#define NTFS_INDEX_ENTRY_NODE
Definition: ntfs.h:60
PB_TREE_FILENAME_NODE CreateBTreeNodeFromIndexNode(PDEVICE_EXTENSION Vcb, PINDEX_ROOT_ATTRIBUTE IndexRoot, PNTFS_ATTR_CONTEXT IndexAllocationAttributeCtx, PINDEX_ENTRY_ATTRIBUTE NodeEntry)
Definition: btree.c:499
VOID DestroyBTree(PB_TREE Tree)
Definition: btree.c:1542
Definition: Header.h:9
static const WCHAR Cleanup[]
Definition: register.c:80
struct INDEX_ENTRY_ATTRIBUTE * PINDEX_ENTRY_ATTRIBUTE
PCONFIGURATION_COMPONENT_DATA RootNode
Definition: macharm.c:19
Definition: ntfs.h:454
Definition: ntfs.h:409
USHORT Length
Definition: ntfs.h:423
ULONG FirstEntryOffset
Definition: ntfs.h:384
ULONG TotalSizeOfEntries
Definition: ntfs.h:385
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:398
B_TREE_FILENAME_NODE * LesserChild
Definition: ntfs.h:437
#define STATUS_FILE_CORRUPT_ERROR
Definition: udferr_usr.h:168

Referenced by NtfsAddFilenameToDirectory().

◆ CreateEmptyBTree()

NTSTATUS CreateEmptyBTree ( PB_TREE NewTree)

Definition at line 348 of file btree.c.

349{
352 PB_TREE_KEY DummyKey;
353
354 DPRINT1("CreateEmptyBTree(%p) called\n", NewTree);
355
356 if (!Tree || !RootNode)
357 {
358 DPRINT1("Couldn't allocate enough memory for B-Tree!\n");
359 if (Tree)
361 if (RootNode)
364 }
365
366 // Create the dummy key
367 DummyKey = CreateDummyKey(FALSE);
368 if (!DummyKey)
369 {
370 DPRINT1("ERROR: Failed to create dummy key!\n");
374 }
375
376 RtlZeroMemory(Tree, sizeof(B_TREE));
378
379 // Setup the Tree
380 RootNode->FirstKey = DummyKey;
381 RootNode->KeyCount = 1;
382 RootNode->DiskNeedsUpdating = TRUE;
383 Tree->RootNode = RootNode;
384
385 *NewTree = Tree;
386
387 // Memory will be freed when DestroyBTree() is called
388
389 return STATUS_SUCCESS;
390}
PB_TREE_KEY CreateDummyKey(BOOLEAN HasChildNode)
Definition: btree.c:289

Referenced by NtfsCreateDirectory().

◆ CreateIndexRootFromBTree()

NTSTATUS CreateIndexRootFromBTree ( PDEVICE_EXTENSION  DeviceExt,
PB_TREE  Tree,
ULONG  MaxIndexSize,
PINDEX_ROOT_ATTRIBUTE IndexRoot,
ULONG Length 
)

Definition at line 910 of file btree.c.

915{
916 ULONG i;
917 PB_TREE_KEY CurrentKey;
918 PINDEX_ENTRY_ATTRIBUTE CurrentNodeEntry;
920 DeviceExt->NtfsInfo.BytesPerFileRecord,
921 TAG_NTFS);
922
923 DPRINT("CreateIndexRootFromBTree(%p, %p, 0x%lx, %p, %p)\n", DeviceExt, Tree, MaxIndexSize, IndexRoot, Length);
924
925#ifndef NDEBUG
927#endif
928
929 if (!NewIndexRoot)
930 {
931 DPRINT1("Failed to allocate memory for Index Root!\n");
933 }
934
935 // Setup the new index root
936 RtlZeroMemory(NewIndexRoot, DeviceExt->NtfsInfo.BytesPerFileRecord);
937
938 NewIndexRoot->AttributeType = AttributeFileName;
939 NewIndexRoot->CollationRule = COLLATION_FILE_NAME;
940 NewIndexRoot->SizeOfEntry = DeviceExt->NtfsInfo.BytesPerIndexRecord;
941 // If Bytes per index record is less than cluster size, clusters per index record becomes sectors per index
942 if (NewIndexRoot->SizeOfEntry < DeviceExt->NtfsInfo.BytesPerCluster)
943 NewIndexRoot->ClustersPerIndexRecord = NewIndexRoot->SizeOfEntry / DeviceExt->NtfsInfo.BytesPerSector;
944 else
945 NewIndexRoot->ClustersPerIndexRecord = NewIndexRoot->SizeOfEntry / DeviceExt->NtfsInfo.BytesPerCluster;
946
947 // Setup the Index node header
948 NewIndexRoot->Header.FirstEntryOffset = sizeof(INDEX_HEADER_ATTRIBUTE);
949 NewIndexRoot->Header.Flags = INDEX_ROOT_SMALL;
950
951 // Start summing the total size of this node's entries
952 NewIndexRoot->Header.TotalSizeOfEntries = NewIndexRoot->Header.FirstEntryOffset;
953
954 // Setup each Node Entry
955 CurrentKey = Tree->RootNode->FirstKey;
956 CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)NewIndexRoot
958 + NewIndexRoot->Header.FirstEntryOffset);
959 for (i = 0; i < Tree->RootNode->KeyCount; i++)
960 {
961 // Would adding the current entry to the index increase the index size beyond the limit we've set?
962 ULONG IndexSize = NewIndexRoot->Header.TotalSizeOfEntries - NewIndexRoot->Header.FirstEntryOffset + CurrentKey->IndexEntry->Length;
963 if (IndexSize > MaxIndexSize)
964 {
965 DPRINT1("TODO: Adding file would require creating an attribute list!\n");
966 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
968 }
969
970 ASSERT(CurrentKey->IndexEntry->Length != 0);
971
972 // Copy the index entry
973 RtlCopyMemory(CurrentNodeEntry, CurrentKey->IndexEntry, CurrentKey->IndexEntry->Length);
974
975 DPRINT1("Index Node Entry Stream Length: %u\nIndex Node Entry Length: %u\n",
976 CurrentNodeEntry->KeyLength,
977 CurrentNodeEntry->Length);
978
979 // Does the current key have any sub-nodes?
980 if (CurrentKey->LesserChild)
981 NewIndexRoot->Header.Flags = INDEX_ROOT_LARGE;
982
983 // Add Length of Current Entry to Total Size of Entries
984 NewIndexRoot->Header.TotalSizeOfEntries += CurrentKey->IndexEntry->Length;
985
986 // Go to the next node entry
987 CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)CurrentNodeEntry + CurrentNodeEntry->Length);
988
989 CurrentKey = CurrentKey->NextKey;
990 }
991
992 NewIndexRoot->Header.AllocatedSize = NewIndexRoot->Header.TotalSizeOfEntries;
993
994 *IndexRoot = NewIndexRoot;
996
997 return STATUS_SUCCESS;
998}
VOID DumpBTree(PB_TREE Tree)
Definition: btree.c:1622
#define INDEX_ROOT_SMALL
Definition: ntfs.h:208
#define COLLATION_FILE_NAME
Definition: ntfs.h:201
#define INDEX_ROOT_LARGE
Definition: ntfs.h:209
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
USHORT KeyLength
Definition: ntfs.h:424
ULONG AttributeType
Definition: ntfs.h:393
ULONG CollationRule
Definition: ntfs.h:394
UCHAR ClustersPerIndexRecord
Definition: ntfs.h:396
ULONG SizeOfEntry
Definition: ntfs.h:395

Referenced by NtfsAddFilenameToDirectory(), and NtfsCreateDirectory().

◆ DecodeRun()

PUCHAR DecodeRun ( PUCHAR  DataRun,
LONGLONG DataRunOffset,
ULONGLONG DataRunLength 
)

Definition at line 966 of file attrib.c.

969{
970 UCHAR DataRunOffsetSize;
971 UCHAR DataRunLengthSize;
972 CHAR i;
973
974 DataRunOffsetSize = (*DataRun >> 4) & 0xF;
975 DataRunLengthSize = *DataRun & 0xF;
976 *DataRunOffset = 0;
977 *DataRunLength = 0;
978 DataRun++;
979 for (i = 0; i < DataRunLengthSize; i++)
980 {
981 *DataRunLength += ((ULONG64)*DataRun) << (i * 8);
982 DataRun++;
983 }
984
985 /* NTFS 3+ sparse files */
986 if (DataRunOffsetSize == 0)
987 {
988 *DataRunOffset = -1;
989 }
990 else
991 {
992 for (i = 0; i < DataRunOffsetSize - 1; i++)
993 {
994 *DataRunOffset += ((ULONG64)*DataRun) << (i * 8);
995 DataRun++;
996 }
997 /* The last byte contains sign so we must process it different way. */
998 *DataRunOffset = ((LONG64)(CHAR)(*(DataRun++)) << (i * 8)) + *DataRunOffset;
999 }
1000
1001 DPRINT("DataRunOffsetSize: %x\n", DataRunOffsetSize);
1002 DPRINT("DataRunLengthSize: %x\n", DataRunLengthSize);
1003 DPRINT("DataRunOffset: %x\n", *DataRunOffset);
1004 DPRINT("DataRunLength: %x\n", *DataRunLength);
1005
1006 return DataRun;
1007}
unsigned __int64 ULONG64
Definition: imports.h:198
int64_t LONG64
Definition: typedefs.h:68
char CHAR
Definition: xmlstorage.h:175

Referenced by ConvertDataRunsToLargeMCB(), FindRun(), GetLastClusterInDataRun(), NtfsDumpDataRuns(), PrepareAttributeContext(), PrintAttributeInfo(), ReadAttribute(), and WriteAttribute().

◆ DemoteBTreeRoot()

NTSTATUS DemoteBTreeRoot ( PB_TREE  Tree)

Definition at line 1089 of file btree.c.

1090{
1091 PB_TREE_FILENAME_NODE NewSubNode, NewIndexRoot;
1092 PB_TREE_KEY DummyKey;
1093
1094 DPRINT("Collapsing Index Root into sub-node.\n");
1095
1096#ifndef NDEBUG
1097 DumpBTree(Tree);
1098#endif
1099
1100 // Create a new node that will hold the keys currently in index root
1102 if (!NewSubNode)
1103 {
1104 DPRINT1("ERROR: Couldn't allocate memory for new sub-node.\n");
1106 }
1107 RtlZeroMemory(NewSubNode, sizeof(B_TREE_FILENAME_NODE));
1108
1109 // Copy the applicable data from the old index root node
1110 NewSubNode->KeyCount = Tree->RootNode->KeyCount;
1111 NewSubNode->FirstKey = Tree->RootNode->FirstKey;
1112 NewSubNode->DiskNeedsUpdating = TRUE;
1113
1114 // Create a new dummy key, and make the new node it's child
1115 DummyKey = CreateDummyKey(TRUE);
1116 if (!DummyKey)
1117 {
1118 DPRINT1("ERROR: Couldn't allocate memory for new root node.\n");
1119 ExFreePoolWithTag(NewSubNode, TAG_NTFS);
1121 }
1122
1123 // Make the new node a child of the dummy key
1124 DummyKey->LesserChild = NewSubNode;
1125
1126 // Create a new index root node
1128 if (!NewIndexRoot)
1129 {
1130 DPRINT1("ERROR: Couldn't allocate memory for new index root.\n");
1131 ExFreePoolWithTag(NewSubNode, TAG_NTFS);
1132 ExFreePoolWithTag(DummyKey, TAG_NTFS);
1134 }
1135 RtlZeroMemory(NewIndexRoot, sizeof(B_TREE_FILENAME_NODE));
1136
1137 NewIndexRoot->DiskNeedsUpdating = TRUE;
1138
1139 // Insert the dummy key into the new node
1140 NewIndexRoot->FirstKey = DummyKey;
1141 NewIndexRoot->KeyCount = 1;
1142 NewIndexRoot->DiskNeedsUpdating = TRUE;
1143
1144 // Make the new node the Tree's root node
1145 Tree->RootNode = NewIndexRoot;
1146
1147#ifndef NDEBUG
1148 DumpBTree(Tree);
1149#endif
1150
1151 return STATUS_SUCCESS;
1152}
BOOLEAN DiskNeedsUpdating
Definition: ntfs.h:448
PB_TREE_KEY FirstKey
Definition: ntfs.h:450

Referenced by NtfsAddFilenameToDirectory().

◆ DestroyBTree()

VOID DestroyBTree ( PB_TREE  Tree)

Definition at line 1542 of file btree.c.

1543{
1544 DestroyBTreeNode(Tree->RootNode);
1546}
VOID DestroyBTreeNode(PB_TREE_FILENAME_NODE Node)
Definition: btree.c:1511

Referenced by CreateBTreeFromIndex(), NtfsAddFilenameToDirectory(), and NtfsCreateDirectory().

◆ DestroyBTreeNode()

VOID DestroyBTreeNode ( PB_TREE_FILENAME_NODE  Node)

Definition at line 1511 of file btree.c.

1512{
1513 PB_TREE_KEY NextKey;
1514 PB_TREE_KEY CurrentKey = Node->FirstKey;
1515 ULONG i;
1516 for (i = 0; i < Node->KeyCount; i++)
1517 {
1518 NT_ASSERT(CurrentKey);
1519 NextKey = CurrentKey->NextKey;
1520 DestroyBTreeKey(CurrentKey);
1521 CurrentKey = NextKey;
1522 }
1523
1524 NT_ASSERT(NextKey == NULL);
1525
1527}
VOID DestroyBTreeKey(PB_TREE_KEY Key)
Definition: btree.c:1499
Definition: dlist.c:348
#define NT_ASSERT
Definition: rtlfuncs.h:3327

Referenced by CreateBTreeNodeFromIndexNode(), DestroyBTree(), and DestroyBTreeKey().

◆ DumpBTree()

VOID DumpBTree ( PB_TREE  Tree)

Definition at line 1622 of file btree.c.

1623{
1624 DbgPrint("B_TREE @ %p\n", Tree);
1625 DumpBTreeNode(Tree, Tree->RootNode, 0, 0);
1626}
VOID DumpBTreeNode(PB_TREE Tree, PB_TREE_FILENAME_NODE Node, ULONG Number, ULONG Depth)
Definition: btree.c:1583
#define DbgPrint
Definition: hal.h:12

Referenced by CreateIndexRootFromBTree(), DemoteBTreeRoot(), NtfsAddFilenameToDirectory(), NtfsInsertKey(), and UpdateIndexAllocation().

◆ DumpBTreeKey()

VOID DumpBTreeKey ( PB_TREE  Tree,
PB_TREE_KEY  Key,
ULONG  Number,
ULONG  Depth 
)

Definition at line 1549 of file btree.c.

1550{
1551 ULONG i;
1552 for (i = 0; i < Depth; i++)
1553 DbgPrint(" ");
1554 DbgPrint(" Key #%d", Number);
1555
1556 if (!(Key->IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
1557 {
1559 FileName.Length = Key->IndexEntry->FileName.NameLength * sizeof(WCHAR);
1560 FileName.MaximumLength = FileName.Length;
1561 FileName.Buffer = Key->IndexEntry->FileName.Name;
1562 DbgPrint(" '%wZ'\n", &FileName);
1563 }
1564 else
1565 {
1566 DbgPrint(" (Dummy Key)\n");
1567 }
1568
1569 // Is there a child node?
1570 if (Key->IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
1571 {
1572 if (Key->LesserChild)
1573 DumpBTreeNode(Tree, Key->LesserChild, Number, Depth + 1);
1574 else
1575 {
1576 // This will be an assert once nodes with arbitrary depth are debugged
1577 DPRINT1("DRIVER ERROR: No Key->LesserChild despite Key->IndexEntry->Flags indicating this is a node!\n");
1578 }
1579 }
1580}
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:207
_In_opt_ PALLOCATE_FUNCTION _In_opt_ PFREE_FUNCTION _In_ ULONG _In_ SIZE_T _In_ ULONG _In_ USHORT Depth
Definition: exfuncs.h:819

Referenced by DumpBTreeNode().

◆ DumpBTreeNode()

VOID DumpBTreeNode ( PB_TREE  Tree,
PB_TREE_FILENAME_NODE  Node,
ULONG  Number,
ULONG  Depth 
)

Definition at line 1583 of file btree.c.

1587{
1588 PB_TREE_KEY CurrentKey;
1589 ULONG i;
1590 for (i = 0; i < Depth; i++)
1591 DbgPrint(" ");
1592 DbgPrint("Node #%d, Depth %d, has %d key%s", Number, Depth, Node->KeyCount, Node->KeyCount == 1 ? "" : "s");
1593
1594 if (Node->HasValidVCN)
1595 DbgPrint(" VCN: %I64u\n", Node->VCN);
1596 else if (Tree->RootNode == Node)
1597 DbgPrint(" Index Root");
1598 else
1599 DbgPrint(" NOT ASSIGNED VCN YET\n");
1600
1601 CurrentKey = Node->FirstKey;
1602 for (i = 0; i < Node->KeyCount; i++)
1603 {
1604 DumpBTreeKey(Tree, CurrentKey, i, Depth);
1605 CurrentKey = CurrentKey->NextKey;
1606 }
1607}
VOID DumpBTreeKey(PB_TREE Tree, PB_TREE_KEY Key, ULONG Number, ULONG Depth)
Definition: btree.c:1549

Referenced by DumpBTree(), DumpBTreeKey(), and SplitBTreeNode().

◆ EnumerAttribute()

VOID EnumerAttribute ( PFILE_RECORD_HEADER  file,
PDEVICE_EXTENSION  Vcb,
PDEVICE_OBJECT  DeviceObject 
)

◆ FindAttribute()

NTSTATUS FindAttribute ( PDEVICE_EXTENSION  Vcb,
PFILE_RECORD_HEADER  MftRecord,
ULONG  Type,
PCWSTR  Name,
ULONG  NameLength,
PNTFS_ATTR_CONTEXT AttrCtx,
PULONG  Offset 
)

Definition at line 131 of file mft.c.

138{
142 PNTFS_ATTR_RECORD Attribute;
143 PNTFS_ATTRIBUTE_LIST_ITEM AttrListItem;
144
145 DPRINT("FindAttribute(%p, %p, 0x%x, %S, %lu, %p, %p)\n", Vcb, MftRecord, Type, Name, NameLength, AttrCtx, Offset);
146
147 Found = FALSE;
148 Status = FindFirstAttribute(&Context, Vcb, MftRecord, FALSE, &Attribute);
149 while (NT_SUCCESS(Status))
150 {
151 if (Attribute->Type == Type && Attribute->NameLength == NameLength)
152 {
153 if (NameLength != 0)
154 {
155 PWCHAR AttrName;
156
157 AttrName = (PWCHAR)((PCHAR)Attribute + Attribute->NameOffset);
158 DPRINT("%.*S, %.*S\n", Attribute->NameLength, AttrName, NameLength, Name);
159 if (RtlCompareMemory(AttrName, Name, NameLength * sizeof(WCHAR)) == (NameLength * sizeof(WCHAR)))
160 {
161 Found = TRUE;
162 }
163 }
164 else
165 {
166 Found = TRUE;
167 }
168
169 if (Found)
170 {
171 /* Found it, fill up the context and return. */
172 DPRINT("Found context\n");
173 *AttrCtx = PrepareAttributeContext(Attribute);
174
175 (*AttrCtx)->FileMFTIndex = MftRecord->MFTRecordNumber;
176
177 if (Offset != NULL)
178 *Offset = Context.Offset;
179
181 return STATUS_SUCCESS;
182 }
183 }
184
185 Status = FindNextAttribute(&Context, &Attribute);
186 }
187
188 /* No attribute found, check if it is referenced in another file record */
189 Status = FindFirstAttributeListItem(&Context, &AttrListItem);
190 while (NT_SUCCESS(Status))
191 {
192 if (AttrListItem->Type == Type && AttrListItem->NameLength == NameLength)
193 {
194 if (NameLength != 0)
195 {
196 PWCHAR AttrName;
197
198 AttrName = (PWCHAR)((PCHAR)AttrListItem + AttrListItem->NameOffset);
199 DPRINT("%.*S, %.*S\n", AttrListItem->NameLength, AttrName, NameLength, Name);
200 if (RtlCompareMemory(AttrName, Name, NameLength * sizeof(WCHAR)) == (NameLength * sizeof(WCHAR)))
201 {
202 Found = TRUE;
203 }
204 }
205 else
206 {
207 Found = TRUE;
208 }
209
210 if (Found == TRUE)
211 {
212 /* Get the MFT Index of attribute */
213 ULONGLONG MftIndex;
214 PFILE_RECORD_HEADER RemoteHdr;
215
216 MftIndex = AttrListItem->MFTIndex & NTFS_MFT_MASK;
217 RemoteHdr = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
218
219 if (RemoteHdr == NULL)
220 {
223 }
224
225 /* Check we are not reading ourselves */
226 if (MftRecord->MFTRecordNumber == MftIndex)
227 {
228 DPRINT1("Attribute list references missing attribute to this file entry !");
229 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, RemoteHdr);
232 }
233 /* Read the new file record */
234 ReadFileRecord(Vcb, MftIndex, RemoteHdr);
235 Status = FindAttribute(Vcb, RemoteHdr, Type, Name, NameLength, AttrCtx, Offset);
236 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, RemoteHdr);
238 return Status;
239 }
240 }
241 Status = FindNextAttributeListItem(&Context, &AttrListItem);
242 }
245}
Type
Definition: Type.h:7
#define NTFS_MFT_MASK
Definition: ntfs.h:68
return Found
Definition: dirsup.c:1270
NTSTATUS FindFirstAttribute(PFIND_ATTR_CONTXT Context, PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord, BOOLEAN OnlyResident, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1383
NTSTATUS FindFirstAttributeListItem(PFIND_ATTR_CONTXT Context, PNTFS_ATTRIBUTE_LIST_ITEM *Item)
Definition: attrib.c:1307
VOID FindCloseAttribute(PFIND_ATTR_CONTXT Context)
Definition: attrib.c:1465
NTSTATUS FindNextAttribute(PFIND_ATTR_CONTXT Context, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1431
NTSTATUS FindNextAttributeListItem(PFIND_ATTR_CONTXT Context, PNTFS_ATTRIBUTE_LIST_ITEM *Item)
Definition: attrib.c:1321
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
PNTFS_ATTR_CONTEXT PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:41
ULONGLONG MFTIndex
Definition: ntfs.h:314
uint16_t * PWCHAR
Definition: typedefs.h:56

Referenced by AddNewMftEntry(), AllocateIndexNode(), BrowseIndexEntries(), CreateBTreeFromIndex(), tinyxml2::XMLElement::FindAttribute(), FindAttribute(), FreeClusters(), GetVolumeBitmap(), IncreaseMftSize(), NtfsAddFilenameToDirectory(), NtfsAllocateClusters(), NtfsCreateFile(), NtfsDirFindFile(), NtfsFindMftRecord(), NtfsGetFileSize(), NtfsGetFreeClusters(), NtfsGetVolumeData(), NtfsReadFCBAttribute(), NtfsReadFile(), NtfsSetEndOfFile(), NtfsWriteFile(), tinyxml2::XMLElement::QueryBoolAttribute(), tinyxml2::XMLElement::QueryDoubleAttribute(), tinyxml2::XMLElement::QueryFloatAttribute(), tinyxml2::XMLElement::QueryIntAttribute(), tinyxml2::XMLElement::QueryUnsignedAttribute(), UpdateFileNameRecord(), UpdateIndexAllocation(), UpdateIndexEntryFileNameSize(), UpdateMftMirror(), and WriteAttribute().

◆ FindCloseAttribute()

VOID FindCloseAttribute ( PFIND_ATTR_CONTXT  Context)

Definition at line 1465 of file attrib.c.

1466{
1467 if (Context->NonResidentStart != NULL)
1468 {
1469 ExFreePoolWithTag(Context->NonResidentStart, TAG_NTFS);
1470 Context->NonResidentStart = NULL;
1471 }
1472}

Referenced by FindAttribute(), GetFileNameFromRecord(), GetNfsVolumeData(), GetStandardInformationFromRecord(), NtfsDumpFileAttributes(), NtfsGetStreamInformation(), NtfsReadFile(), and NtfsWriteFile().

◆ FindFirstAttribute()

NTSTATUS FindFirstAttribute ( PFIND_ATTR_CONTXT  Context,
PDEVICE_EXTENSION  Vcb,
PFILE_RECORD_HEADER  FileRecord,
BOOLEAN  OnlyResident,
PNTFS_ATTR_RECORD Attribute 
)

Definition at line 1383 of file attrib.c.

1388{
1390
1391 DPRINT("FindFistAttribute(%p, %p, %p, %p, %u, %p)\n", Context, Vcb, FileRecord, OnlyResident, Attribute);
1392
1393 Context->Vcb = Vcb;
1394 Context->OnlyResident = OnlyResident;
1395 Context->FirstAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
1396 Context->CurrAttr = Context->FirstAttr;
1397 Context->LastAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse);
1398 Context->NonResidentStart = NULL;
1399 Context->NonResidentEnd = NULL;
1400 Context->Offset = FileRecord->AttributeOffset;
1401
1402 if (Context->FirstAttr->Type == AttributeEnd)
1403 {
1404 Context->CurrAttr = (PVOID)-1;
1405 return STATUS_END_OF_FILE;
1406 }
1407 else if (Context->FirstAttr->Type == AttributeAttributeList)
1408 {
1410 if (!NT_SUCCESS(Status))
1411 {
1412 return Status;
1413 }
1414
1415 *Attribute = InternalGetNextAttribute(Context);
1416 if (*Attribute == NULL)
1417 {
1418 return STATUS_END_OF_FILE;
1419 }
1420 }
1421 else
1422 {
1423 *Attribute = Context->CurrAttr;
1424 Context->Offset = (UCHAR*)Context->CurrAttr - (UCHAR*)FileRecord;
1425 }
1426
1427 return STATUS_SUCCESS;
1428}
static NTSTATUS InternalReadNonResidentAttributes(PFIND_ATTR_CONTXT Context)
Definition: attrib.c:1214
static PNTFS_ATTR_RECORD InternalGetNextAttribute(PFIND_ATTR_CONTXT Context)
Definition: attrib.c:1334
#define STATUS_END_OF_FILE
Definition: shellext.h:67
USHORT AttributeOffset
Definition: ntfs.h:255
void * PVOID
Definition: typedefs.h:50

Referenced by FindAttribute(), GetFileNameFromRecord(), GetNfsVolumeData(), GetStandardInformationFromRecord(), NtfsDumpFileAttributes(), NtfsGetStreamInformation(), NtfsReadFile(), and NtfsWriteFile().

◆ FindFirstAttributeListItem()

NTSTATUS FindFirstAttributeListItem ( PFIND_ATTR_CONTXT  Context,
PNTFS_ATTRIBUTE_LIST_ITEM Item 
)

Definition at line 1307 of file attrib.c.

1309{
1310 if (Context->NonResidentStart == NULL || Context->NonResidentStart->Type == AttributeEnd)
1311 {
1312 return STATUS_UNSUCCESSFUL;
1313 }
1314
1315 Context->NonResidentCur = Context->NonResidentStart;
1316 *Item = Context->NonResidentCur;
1317 return STATUS_SUCCESS;
1318}
_In_ WDFCOLLECTION _In_ WDFOBJECT Item

Referenced by FindAttribute().

◆ FindNextAttribute()

NTSTATUS FindNextAttribute ( PFIND_ATTR_CONTXT  Context,
PNTFS_ATTR_RECORD Attribute 
)

Definition at line 1431 of file attrib.c.

1433{
1435
1436 DPRINT("FindNextAttribute(%p, %p)\n", Context, Attribute);
1437
1438 *Attribute = InternalGetNextAttribute(Context);
1439 if (*Attribute == NULL)
1440 {
1441 return STATUS_END_OF_FILE;
1442 }
1443
1444 if (Context->CurrAttr->Type != AttributeAttributeList)
1445 {
1446 return STATUS_SUCCESS;
1447 }
1448
1450 if (!NT_SUCCESS(Status))
1451 {
1452 return Status;
1453 }
1454
1455 *Attribute = InternalGetNextAttribute(Context);
1456 if (*Attribute == NULL)
1457 {
1458 return STATUS_END_OF_FILE;
1459 }
1460
1461 return STATUS_SUCCESS;
1462}

Referenced by FindAttribute(), GetFileNameFromRecord(), GetNfsVolumeData(), GetStandardInformationFromRecord(), NtfsDumpFileAttributes(), NtfsGetStreamInformation(), NtfsReadFile(), and NtfsWriteFile().

◆ FindNextAttributeListItem()

NTSTATUS FindNextAttributeListItem ( PFIND_ATTR_CONTXT  Context,
PNTFS_ATTRIBUTE_LIST_ITEM Item 
)

Definition at line 1321 of file attrib.c.

1323{
1325 if (*Item == NULL)
1326 {
1327 return STATUS_UNSUCCESSFUL;
1328 }
1329 return STATUS_SUCCESS;
1330}
static PNTFS_ATTRIBUTE_LIST_ITEM InternalGetNextAttributeListItem(PFIND_ATTR_CONTXT Context)
Definition: attrib.c:1267

Referenced by FindAttribute().

◆ FixupUpdateSequenceArray()

NTSTATUS FixupUpdateSequenceArray ( PDEVICE_EXTENSION  Vcb,
PNTFS_RECORD_HEADER  Record 
)

Definition at line 1965 of file mft.c.

1967{
1968 USHORT *USA;
1969 USHORT USANumber;
1970 USHORT USACount;
1971 USHORT *Block;
1972
1973 USA = (USHORT*)((PCHAR)Record + Record->UsaOffset);
1974 USANumber = *(USA++);
1975 USACount = Record->UsaCount - 1; /* Exclude the USA Number. */
1976 Block = (USHORT*)((PCHAR)Record + Vcb->NtfsInfo.BytesPerSector - 2);
1977
1978 DPRINT("FixupUpdateSequenceArray(%p, %p)\nUSANumber: %u\tUSACount: %u\n", Vcb, Record, USANumber, USACount);
1979
1980 while (USACount)
1981 {
1982 if (*Block != USANumber)
1983 {
1984 DPRINT1("Mismatch with USA: %u read, %u expected\n" , *Block, USANumber);
1985 return STATUS_UNSUCCESSFUL;
1986 }
1987 *Block = *(USA++);
1988 Block = (USHORT*)((PCHAR)Block + Vcb->NtfsInfo.BytesPerSector);
1989 USACount--;
1990 }
1991
1992 return STATUS_SUCCESS;
1993}

Referenced by BrowseSubNodeIndexEntries(), CreateBTreeNodeFromIndexNode(), PrintAllVCNs(), ReadFileRecord(), UpdateFileRecord(), and UpdateIndexEntryFileNameSize().

◆ FreeClusters()

NTSTATUS FreeClusters ( PNTFS_VCB  Vcb,
PNTFS_ATTR_CONTEXT  AttrContext,
ULONG  AttrOffset,
PFILE_RECORD_HEADER  FileRecord,
ULONG  ClustersToFree 
)

Definition at line 1057 of file attrib.c.

1062{
1064 ULONG ClustersLeftToFree = ClustersToFree;
1065
1066 PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
1067 ULONG NextAttributeOffset = AttrOffset + AttrContext->pRecord->Length;
1068 PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
1069
1070 PUCHAR RunBuffer;
1071 ULONG RunBufferSize = 0;
1072
1073 PFILE_RECORD_HEADER BitmapRecord;
1074 PNTFS_ATTR_CONTEXT DataContext;
1075 ULONGLONG BitmapDataSize;
1078 ULONG LengthWritten;
1079
1080 if (!AttrContext->pRecord->IsNonResident)
1081 {
1083 }
1084
1085 // Read the $Bitmap file
1086 BitmapRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
1087 if (BitmapRecord == NULL)
1088 {
1089 DPRINT1("Error: Unable to allocate memory for bitmap file record!\n");
1090 return STATUS_NO_MEMORY;
1091 }
1092
1093 Status = ReadFileRecord(Vcb, NTFS_FILE_BITMAP, BitmapRecord);
1094 if (!NT_SUCCESS(Status))
1095 {
1096 DPRINT1("Error: Unable to read file record for bitmap!\n");
1097 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BitmapRecord);
1098 return 0;
1099 }
1100
1101 Status = FindAttribute(Vcb, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL);
1102 if (!NT_SUCCESS(Status))
1103 {
1104 DPRINT1("Error: Unable to find data attribute for bitmap file!\n");
1105 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BitmapRecord);
1106 return 0;
1107 }
1108
1109 BitmapDataSize = AttributeDataLength(DataContext->pRecord);
1110 BitmapDataSize = min(BitmapDataSize, ULONG_MAX);
1111 ASSERT((BitmapDataSize * 8) >= Vcb->NtfsInfo.ClusterCount);
1112 BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, Vcb->NtfsInfo.BytesPerSector), TAG_NTFS);
1113 if (BitmapData == NULL)
1114 {
1115 DPRINT1("Error: Unable to allocate memory for bitmap file data!\n");
1116 ReleaseAttributeContext(DataContext);
1117 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BitmapRecord);
1118 return 0;
1119 }
1120
1121 ReadAttribute(Vcb, DataContext, 0, (PCHAR)BitmapData, (ULONG)BitmapDataSize);
1122
1123 RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, Vcb->NtfsInfo.ClusterCount);
1124
1125 // free clusters in $BITMAP file
1126 while (ClustersLeftToFree > 0)
1127 {
1129
1130 if (!FsRtlLookupLastLargeMcbEntry(&AttrContext->DataRunsMCB, &LargeVbn, &LargeLbn))
1131 {
1133 DPRINT1("DRIVER ERROR: FreeClusters called to free %lu clusters, which is %lu more clusters than are assigned to attribute!",
1134 ClustersToFree,
1135 ClustersLeftToFree);
1136 break;
1137 }
1138
1139 if (LargeLbn != -1)
1140 {
1141 // deallocate this cluster
1143 }
1144 FsRtlTruncateLargeMcb(&AttrContext->DataRunsMCB, AttrContext->pRecord->NonResident.HighestVCN);
1145
1146 // decrement HighestVCN, but don't let it go below 0
1147 AttrContext->pRecord->NonResident.HighestVCN = min(AttrContext->pRecord->NonResident.HighestVCN, AttrContext->pRecord->NonResident.HighestVCN - 1);
1148 ClustersLeftToFree--;
1149 }
1150
1151 // update $BITMAP file on disk
1152 Status = WriteAttribute(Vcb, DataContext, 0, BitmapData, (ULONG)BitmapDataSize, &LengthWritten, FileRecord);
1153 if (!NT_SUCCESS(Status))
1154 {
1155 ReleaseAttributeContext(DataContext);
1157 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BitmapRecord);
1158 return Status;
1159 }
1160
1161 ReleaseAttributeContext(DataContext);
1163 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BitmapRecord);
1164
1165 // Save updated data runs to file record
1166
1167 // Allocate some memory for a new RunBuffer
1168 RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
1169 if (!RunBuffer)
1170 {
1171 DPRINT1("ERROR: Couldn't allocate memory for data runs!\n");
1173 }
1174
1175 // Convert the map control block back to encoded data runs
1176 ConvertLargeMCBToDataRuns(&AttrContext->DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferSize);
1177
1178 // Update HighestVCN
1179 DestinationAttribute->NonResident.HighestVCN = AttrContext->pRecord->NonResident.HighestVCN;
1180
1181 // Write data runs to destination attribute
1182 RtlCopyMemory((PVOID)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset),
1183 RunBuffer,
1184 RunBufferSize);
1185
1186 // Is DestinationAttribute the last attribute in the file record?
1187 if (NextAttribute->Type == AttributeEnd)
1188 {
1189 // update attribute length
1190 DestinationAttribute->Length = ALIGN_UP_BY(AttrContext->pRecord->NonResident.MappingPairsOffset + RunBufferSize,
1192
1193 ASSERT(DestinationAttribute->Length <= AttrContext->pRecord->Length);
1194
1195 AttrContext->pRecord->Length = DestinationAttribute->Length;
1196
1197 // write end markers
1198 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + DestinationAttribute->Length);
1199 SetFileRecordEnd(FileRecord, NextAttribute, FILE_RECORD_END);
1200 }
1201
1202 // Update the file record
1203 Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord);
1204
1205 ExFreePoolWithTag(RunBuffer, TAG_NTFS);
1206
1207 NtfsDumpDataRuns((PUCHAR)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), 0);
1208
1209 return Status;
1210}
#define NTFS_FILE_BITMAP
Definition: ntfs.h:29
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#define RtlClearBits
Definition: dbgbitmap.h:331
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
_Out_ PLONGLONG LargeVbn
Definition: fsrtlfuncs.h:520
_Out_ PLONGLONG _Out_ PLONGLONG LargeLbn
Definition: fsrtlfuncs.h:521
#define ULONG_MAX
Definition: intsafe.h:155
VOID NTAPI FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb, IN LONGLONG Vbn)
Definition: largemcb.c:1059
BOOLEAN NTAPI FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb, OUT PLONGLONG Vbn, OUT PLONGLONG Lbn)
Definition: largemcb.c:718
#define min(a, b)
Definition: monoChain.cc:55

Referenced by FatExamineFatEntries(), GetDiskFreeSpaceW(), HandleNotify(), NtfsAllocateClusters(), NtfsGetFreeClusters(), and SetNonResidentAttributeDataLength().

◆ GetAllocationOffsetFromVCN()

ULONGLONG GetAllocationOffsetFromVCN ( PDEVICE_EXTENSION  DeviceExt,
ULONG  IndexBufferSize,
ULONGLONG  Vcn 
)

Definition at line 1630 of file btree.c.

1633{
1634 if (IndexBufferSize < DeviceExt->NtfsInfo.BytesPerCluster)
1635 return Vcn * DeviceExt->NtfsInfo.BytesPerSector;
1636
1637 return Vcn * DeviceExt->NtfsInfo.BytesPerCluster;
1638}

Referenced by CreateBTreeNodeFromIndexNode(), and UpdateIndexNode().

◆ GetBestFileNameFromRecord()

PFILENAME_ATTRIBUTE GetBestFileNameFromRecord ( PDEVICE_EXTENSION  Vcb,
PFILE_RECORD_HEADER  FileRecord 
)

Definition at line 1985 of file attrib.c.

1987{
1989
1991 if (FileName == NULL)
1992 {
1994 if (FileName == NULL)
1995 {
1997 }
1998 }
1999
2000 return FileName;
2001}
#define NTFS_FILE_NAME_DOS
Definition: ntfs.h:65
#define NTFS_FILE_NAME_WIN32
Definition: ntfs.h:64
PFILENAME_ATTRIBUTE GetFileNameFromRecord(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord, UCHAR NameType)
Definition: attrib.c:1809

Referenced by NtfsGetBothDirectoryInformation(), NtfsGetDirectoryInformation(), NtfsGetFullDirectoryInformation(), NtfsGetNamesInformation(), NtfsMakeFCBFromDirEntry(), NtfsMoonWalkID(), NtfsSetEndOfFile(), and NtfsWriteFile().

◆ GetFileNameAttributeLength()

ULONG GetFileNameAttributeLength ( PFILENAME_ATTRIBUTE  FileNameAttribute)

Definition at line 1978 of file attrib.c.

1979{
1980 ULONG Length = FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + (FileNameAttribute->NameLength * sizeof(WCHAR));
1981 return Length;
1982}

Referenced by CreateBTreeKeyFromFilename().

◆ GetFileNameFromRecord()

PFILENAME_ATTRIBUTE GetFileNameFromRecord ( PDEVICE_EXTENSION  Vcb,
PFILE_RECORD_HEADER  FileRecord,
UCHAR  NameType 
)

Definition at line 1809 of file attrib.c.

1812{
1814 PNTFS_ATTR_RECORD Attribute;
1817
1818 Status = FindFirstAttribute(&Context, Vcb, FileRecord, FALSE, &Attribute);
1819 while (NT_SUCCESS(Status))
1820 {
1821 if (Attribute->Type == AttributeFileName)
1822 {
1823 Name = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
1824 if (Name->NameType == NameType ||
1827 {
1829 return Name;
1830 }
1831 }
1832
1833 Status = FindNextAttribute(&Context, &Attribute);
1834 }
1835
1837 return NULL;
1838}
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn UINT32 *TableIdx UINT32 ACPI_TABLE_HEADER *OutTableHeader ACPI_TABLE_HEADER **OutTable ACPI_HANDLE UINT32 ACPI_WALK_CALLBACK ACPI_WALK_CALLBACK void void **ReturnValue UINT32 NameType
Definition: acpixf.h:658
struct NameRec_ * Name
Definition: cdprocs.h:460

Referenced by GetBestFileNameFromRecord(), NtfsGetBothDirectoryInformation(), and NtfsMakeRootFCB().

◆ GetIndexEntryVCN()

ULONGLONG GetIndexEntryVCN ( PINDEX_ENTRY_ATTRIBUTE  IndexEntry)

Definition at line 1641 of file btree.c.

1642{
1643 PULONGLONG Destination = (PULONGLONG)((ULONG_PTR)IndexEntry + IndexEntry->Length - sizeof(ULONGLONG));
1644
1645 ASSERT(IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE);
1646
1647 return *Destination;
1648}
_In_ PUNICODE_STRING _Inout_ PUNICODE_STRING Destination
Definition: rtlfuncs.h:3016
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:391

Referenced by BrowseIndexEntries(), BrowseSubNodeIndexEntries(), and SplitBTreeNode().

◆ GetLastClusterInDataRun()

NTSTATUS GetLastClusterInDataRun ( PDEVICE_EXTENSION  Vcb,
PNTFS_ATTR_RECORD  Attribute,
PULONGLONG  LastCluster 
)

Definition at line 1908 of file attrib.c.

1909{
1910 LONGLONG DataRunOffset;
1911 ULONGLONG DataRunLength;
1912 LONGLONG DataRunStartLCN;
1913
1914 ULONGLONG LastLCN = 0;
1915 PUCHAR DataRun = (PUCHAR)Attribute + Attribute->NonResident.MappingPairsOffset;
1916
1917 if (!Attribute->IsNonResident)
1919
1920 while (1)
1921 {
1922 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1923
1924 if (DataRunOffset != -1)
1925 {
1926 // Normal data run.
1927 DataRunStartLCN = LastLCN + DataRunOffset;
1928 LastLCN = DataRunStartLCN;
1929 *LastCluster = LastLCN + DataRunLength - 1;
1930 }
1931
1932 if (*DataRun == 0)
1933 break;
1934 }
1935
1936 return STATUS_SUCCESS;
1937}
if(dx< 0)
Definition: linetemp.h:194

◆ GetPackedByteCount()

UCHAR GetPackedByteCount ( LONGLONG  NumberToPack,
BOOLEAN  IsSigned 
)

GetPackedByteCount Returns the minimum number of bytes needed to represent the value of a 64-bit number. Used to encode data runs.

Definition at line 1846 of file attrib.c.

1848{
1849 if (!IsSigned)
1850 {
1851 if (NumberToPack >= 0x0100000000000000)
1852 return 8;
1853 if (NumberToPack >= 0x0001000000000000)
1854 return 7;
1855 if (NumberToPack >= 0x0000010000000000)
1856 return 6;
1857 if (NumberToPack >= 0x0000000100000000)
1858 return 5;
1859 if (NumberToPack >= 0x0000000001000000)
1860 return 4;
1861 if (NumberToPack >= 0x0000000000010000)
1862 return 3;
1863 if (NumberToPack >= 0x0000000000000100)
1864 return 2;
1865 return 1;
1866 }
1867
1868 if (NumberToPack > 0)
1869 {
1870 // we have to make sure the number that gets encoded won't be interpreted as negative
1871 if (NumberToPack >= 0x0080000000000000)
1872 return 8;
1873 if (NumberToPack >= 0x0000800000000000)
1874 return 7;
1875 if (NumberToPack >= 0x0000008000000000)
1876 return 6;
1877 if (NumberToPack >= 0x0000000080000000)
1878 return 5;
1879 if (NumberToPack >= 0x0000000000800000)
1880 return 4;
1881 if (NumberToPack >= 0x0000000000008000)
1882 return 3;
1883 if (NumberToPack >= 0x0000000000000080)
1884 return 2;
1885 }
1886 else
1887 {
1888 // negative number
1889 if (NumberToPack <= 0xff80000000000000)
1890 return 8;
1891 if (NumberToPack <= 0xffff800000000000)
1892 return 7;
1893 if (NumberToPack <= 0xffffff8000000000)
1894 return 6;
1895 if (NumberToPack <= 0xffffffff80000000)
1896 return 5;
1897 if (NumberToPack <= 0xffffffffff800000)
1898 return 4;
1899 if (NumberToPack <= 0xffffffffffff8000)
1900 return 3;
1901 if (NumberToPack <= 0xffffffffffffff80)
1902 return 2;
1903 }
1904 return 1;
1905}

Referenced by ConvertLargeMCBToDataRuns().

◆ GetSizeOfIndexEntries()

ULONG GetSizeOfIndexEntries ( PB_TREE_FILENAME_NODE  Node)

Definition at line 855 of file btree.c.

856{
857 // Start summing the total size of this node's entries
858 ULONG NodeSize = 0;
859
860 // Walk through the list of Node Entries
861 PB_TREE_KEY CurrentKey = Node->FirstKey;
862 ULONG i;
863 for (i = 0; i < Node->KeyCount; i++)
864 {
865 ASSERT(CurrentKey->IndexEntry->Length != 0);
866
867 // Add the length of the current node
868 NodeSize += CurrentKey->IndexEntry->Length;
869 CurrentKey = CurrentKey->NextKey;
870 }
871
872 return NodeSize;
873}

Referenced by NtfsAddFilenameToDirectory(), and NtfsInsertKey().

◆ GetStandardInformationFromRecord()

PSTANDARD_INFORMATION GetStandardInformationFromRecord ( PDEVICE_EXTENSION  Vcb,
PFILE_RECORD_HEADER  FileRecord 
)

Definition at line 1940 of file attrib.c.

1942{
1945 PNTFS_ATTR_RECORD Attribute;
1946 PSTANDARD_INFORMATION StdInfo;
1947
1948 Status = FindFirstAttribute(&Context, Vcb, FileRecord, FALSE, &Attribute);
1949 while (NT_SUCCESS(Status))
1950 {
1951 if (Attribute->Type == AttributeStandardInformation)
1952 {
1953 StdInfo = (PSTANDARD_INFORMATION)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
1955 return StdInfo;
1956 }
1957
1958 Status = FindNextAttribute(&Context, &Attribute);
1959 }
1960
1962 return NULL;
1963}

Referenced by NtfsGetBothDirectoryInformation(), NtfsGetDirectoryInformation(), NtfsGetFullDirectoryInformation(), and NtfsMakeFCBFromDirEntry().

◆ InternalSetResidentAttributeLength()

NTSTATUS InternalSetResidentAttributeLength ( PDEVICE_EXTENSION  DeviceExt,
PNTFS_ATTR_CONTEXT  AttrContext,
PFILE_RECORD_HEADER  FileRecord,
ULONG  AttrOffset,
ULONG  DataSize 
)

Definition at line 542 of file mft.c.

547{
548 PNTFS_ATTR_RECORD Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
550 PNTFS_ATTR_RECORD FinalAttribute;
551 ULONG OldAttributeLength = Destination->Length;
552 ULONG NextAttributeOffset;
553
554 DPRINT1("InternalSetResidentAttributeLength( %p, %p, %p, %lu, %lu )\n", DeviceExt, AttrContext, FileRecord, AttrOffset, DataSize);
555
556 ASSERT(!AttrContext->pRecord->IsNonResident);
557
558 // Update ValueLength Field
559 Destination->Resident.ValueLength = DataSize;
560
561 // Calculate the record length and end marker offset
562 Destination->Length = ALIGN_UP_BY(DataSize + AttrContext->pRecord->Resident.ValueOffset, ATTR_RECORD_ALIGNMENT);
563 NextAttributeOffset = AttrOffset + Destination->Length;
564
565 // Ensure NextAttributeOffset is aligned to an 8-byte boundary
566 ASSERT(NextAttributeOffset % ATTR_RECORD_ALIGNMENT == 0);
567
568 // Will the new attribute be larger than the old one?
569 if (Destination->Length > OldAttributeLength)
570 {
571 // Free the old copy of the attribute in the context, as it will be the wrong length
572 ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS);
573
574 // Create a new copy of the attribute record for the context
576 if (!AttrContext->pRecord)
577 {
578 DPRINT1("Unable to allocate memory for attribute!\n");
580 }
581 RtlZeroMemory((PVOID)((ULONG_PTR)AttrContext->pRecord + OldAttributeLength), Destination->Length - OldAttributeLength);
582 RtlCopyMemory(AttrContext->pRecord, Destination, OldAttributeLength);
583 }
584
585 // Are there attributes after this one that need to be moved?
586 if (NextAttribute->Type != AttributeEnd)
587 {
588 // Move the attributes after this one
589 FinalAttribute = MoveAttributes(DeviceExt, NextAttribute, NextAttributeOffset, (ULONG_PTR)Destination + Destination->Length);
590 }
591 else
592 {
593 // advance to the final "attribute," adjust for the changed length of the attribute we're resizing
594 FinalAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute - OldAttributeLength + Destination->Length);
595 }
596
597 // Update pRecord's length
598 AttrContext->pRecord->Length = Destination->Length;
599 AttrContext->pRecord->Resident.ValueLength = DataSize;
600
601 // set the file record end
602 SetFileRecordEnd(FileRecord, FinalAttribute, FILE_RECORD_END);
603
604 //NtfsDumpFileRecord(DeviceExt, FileRecord);
605
606 return STATUS_SUCCESS;
607}
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4755

Referenced by NtfsAddFilenameToDirectory(), and SetResidentAttributeDataLength().

◆ MoveAttributes()

PNTFS_ATTR_RECORD MoveAttributes ( PDEVICE_EXTENSION  DeviceExt,
PNTFS_ATTR_RECORD  FirstAttributeToMove,
ULONG  FirstAttributeOffset,
ULONG_PTR  MoveTo 
)

Definition at line 512 of file mft.c.

516{
517 // Get the size of all attributes after this one
518 ULONG MemBlockSize = 0;
519 PNTFS_ATTR_RECORD CurrentAttribute = FirstAttributeToMove;
520 ULONG CurrentOffset = FirstAttributeOffset;
521 PNTFS_ATTR_RECORD FinalAttribute;
522
523 while (CurrentAttribute->Type != AttributeEnd && CurrentOffset < DeviceExt->NtfsInfo.BytesPerFileRecord)
524 {
525 CurrentOffset += CurrentAttribute->Length;
526 MemBlockSize += CurrentAttribute->Length;
527 CurrentAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)CurrentAttribute + CurrentAttribute->Length);
528 }
529
530 FinalAttribute = (PNTFS_ATTR_RECORD)(MoveTo + MemBlockSize);
531 MemBlockSize += sizeof(ULONG) * 2; // Add the AttributeEnd and file record end
532
533 ASSERT(MemBlockSize % ATTR_RECORD_ALIGNMENT == 0);
534
535 // Move the attributes after this one
536 RtlMoveMemory((PCHAR)MoveTo, FirstAttributeToMove, MemBlockSize);
537
538 return FinalAttribute;
539}
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264

Referenced by AddRun(), and InternalSetResidentAttributeLength().

◆ NtfsAcqLazyWrite()

BOOLEAN NTAPI NtfsAcqLazyWrite ( PVOID  Context,
BOOLEAN  Wait 
)

Definition at line 39 of file fastio.c.

41{
45 return FALSE;
46}
#define UNIMPLEMENTED
Definition: ntoskrnl.c:15
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170

Referenced by DriverEntry().

◆ NtfsAcqReadAhead()

BOOLEAN NTAPI NtfsAcqReadAhead ( PVOID  Context,
BOOLEAN  Wait 
)

Definition at line 60 of file fastio.c.

Referenced by DriverEntry().

◆ NtfsAddFCBToTable()

VOID NtfsAddFCBToTable ( PNTFS_VCB  Vcb,
PNTFS_FCB  Fcb 
)

Definition at line 209 of file fcb.c.

211{
212 KIRQL oldIrql;
213
214 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
215 Fcb->Vcb = Vcb;
216 InsertTailList(&Vcb->FcbListHead, &Fcb->FcbListEntry);
217 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
218}
_In_ PFCB Fcb
Definition: cdprocs.h:159
#define InsertTailList(ListHead, Entry)
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
PVCB Vcb
Definition: cdstruc.h:933
LIST_ENTRY FcbListEntry
Definition: ntfs.h:530

Referenced by NtfsMakeFCBFromDirEntry(), and NtfsMakeRootFCB().

◆ NtfsAddFilenameToDirectory()

NTSTATUS NtfsAddFilenameToDirectory ( PDEVICE_EXTENSION  DeviceExt,
ULONGLONG  DirectoryMftIndex,
ULONGLONG  FileReferenceNumber,
PFILENAME_ATTRIBUTE  FilenameAttribute,
BOOLEAN  CaseSensitive 
)

Definition at line 2192 of file mft.c.

2197{
2199 PFILE_RECORD_HEADER ParentFileRecord;
2200 PNTFS_ATTR_CONTEXT IndexRootContext;
2201 PINDEX_ROOT_ATTRIBUTE I30IndexRoot;
2202 ULONG IndexRootOffset;
2203 ULONGLONG I30IndexRootLength;
2204 ULONG LengthWritten;
2205 PINDEX_ROOT_ATTRIBUTE NewIndexRoot;
2206 ULONG AttributeLength;
2207 PNTFS_ATTR_RECORD NextAttribute;
2208 PB_TREE NewTree;
2209 ULONG BtreeIndexLength;
2210 ULONG MaxIndexRootSize;
2211 PB_TREE_KEY NewLeftKey;
2212 PB_TREE_FILENAME_NODE NewRightHandNode;
2213 LARGE_INTEGER MinIndexRootSize;
2214 ULONG NewMaxIndexRootSize;
2215 ULONG NodeSize;
2216
2217 // Allocate memory for the parent directory
2218 ParentFileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
2219 if (!ParentFileRecord)
2220 {
2221 DPRINT1("ERROR: Couldn't allocate memory for file record!\n");
2223 }
2224
2225 // Open the parent directory
2226 Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
2227 if (!NT_SUCCESS(Status))
2228 {
2229 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2230 DPRINT1("ERROR: Couldn't read parent directory with index %I64u\n",
2231 DirectoryMftIndex);
2232 return Status;
2233 }
2234
2235#ifndef NDEBUG
2236 DPRINT1("Dumping old parent file record:\n");
2237 NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
2238#endif
2239
2240 // Find the index root attribute for the directory
2241 Status = FindAttribute(DeviceExt,
2242 ParentFileRecord,
2244 L"$I30",
2245 4,
2246 &IndexRootContext,
2247 &IndexRootOffset);
2248 if (!NT_SUCCESS(Status))
2249 {
2250 DPRINT1("ERROR: Couldn't find $I30 $INDEX_ROOT attribute for parent directory with MFT #: %I64u!\n",
2251 DirectoryMftIndex);
2252 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2253 return Status;
2254 }
2255
2256 // Find the maximum index size given what the file record can hold
2257 // First, find the max index size assuming index root is the last attribute
2258 MaxIndexRootSize = DeviceExt->NtfsInfo.BytesPerFileRecord // Start with the size of a file record
2259 - IndexRootOffset // Subtract the length of everything that comes before index root
2260 - IndexRootContext->pRecord->Resident.ValueOffset // Subtract the length of the attribute header for index root
2261 - sizeof(INDEX_ROOT_ATTRIBUTE) // Subtract the length of the index root header
2262 - (sizeof(ULONG) * 2); // Subtract the length of the file record end marker and padding
2263
2264 // Are there attributes after this one?
2265 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset + IndexRootContext->pRecord->Length);
2266 if (NextAttribute->Type != AttributeEnd)
2267 {
2268 // Find the length of all attributes after this one, not counting the end marker
2269 ULONG LengthOfAttributes = 0;
2270 PNTFS_ATTR_RECORD CurrentAttribute = NextAttribute;
2271 while (CurrentAttribute->Type != AttributeEnd)
2272 {
2273 LengthOfAttributes += CurrentAttribute->Length;
2274 CurrentAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)CurrentAttribute + CurrentAttribute->Length);
2275 }
2276
2277 // Leave room for the existing attributes
2278 MaxIndexRootSize -= LengthOfAttributes;
2279 }
2280
2281 // Allocate memory for the index root data
2282 I30IndexRootLength = AttributeDataLength(IndexRootContext->pRecord);
2283 I30IndexRoot = ExAllocatePoolWithTag(NonPagedPool, I30IndexRootLength, TAG_NTFS);
2284 if (!I30IndexRoot)
2285 {
2286 DPRINT1("ERROR: Couldn't allocate memory for index root attribute!\n");
2287 ReleaseAttributeContext(IndexRootContext);
2288 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2290 }
2291
2292 // Read the Index Root
2293 Status = ReadAttribute(DeviceExt, IndexRootContext, 0, (PCHAR)I30IndexRoot, I30IndexRootLength);
2294 if (!NT_SUCCESS(Status))
2295 {
2296 DPRINT1("ERROR: Couln't read index root attribute for Mft index #%I64u\n", DirectoryMftIndex);
2297 ReleaseAttributeContext(IndexRootContext);
2298 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2299 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2300 return Status;
2301 }
2302
2303 // Convert the index to a B*Tree
2304 Status = CreateBTreeFromIndex(DeviceExt,
2305 ParentFileRecord,
2306 IndexRootContext,
2307 I30IndexRoot,
2308 &NewTree);
2309 if (!NT_SUCCESS(Status))
2310 {
2311 DPRINT1("ERROR: Failed to create B-Tree from Index!\n");
2312 ReleaseAttributeContext(IndexRootContext);
2313 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2314 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2315 return Status;
2316 }
2317
2318#ifndef NDEBUG
2319 DumpBTree(NewTree);
2320#endif
2321
2322 // Insert the key for the file we're adding
2323 Status = NtfsInsertKey(NewTree,
2324 FileReferenceNumber,
2325 FilenameAttribute,
2326 NewTree->RootNode,
2327 CaseSensitive,
2328 MaxIndexRootSize,
2329 I30IndexRoot->SizeOfEntry,
2330 &NewLeftKey,
2331 &NewRightHandNode);
2332 if (!NT_SUCCESS(Status))
2333 {
2334 DPRINT1("ERROR: Failed to insert key into B-Tree!\n");
2335 DestroyBTree(NewTree);
2336 ReleaseAttributeContext(IndexRootContext);
2337 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2338 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2339 return Status;
2340 }
2341
2342#ifndef NDEBUG
2343 DumpBTree(NewTree);
2344#endif
2345
2346 // The root node can't be split
2347 ASSERT(NewLeftKey == NULL);
2348 ASSERT(NewRightHandNode == NULL);
2349
2350 // Convert B*Tree back to Index
2351
2352 // Updating the index allocation can change the size available for the index root,
2353 // And if the index root is demoted, the index allocation will need to be updated again,
2354 // which may change the size available for index root... etc.
2355 // My solution is to decrease index root to the size it would be if it was demoted,
2356 // then UpdateIndexAllocation will have an accurate representation of the maximum space
2357 // it can use in the file record. There's still a chance that the act of allocating an
2358 // index node after demoting the index root will increase the size of the file record beyond
2359 // it's limit, but if that happens, an attribute-list will most definitely be needed.
2360 // This a bit hacky, but it seems to be functional.
2361
2362 // Calculate the minimum size of the index root attribute, considering one dummy key and one VCN
2363 MinIndexRootSize.QuadPart = sizeof(INDEX_ROOT_ATTRIBUTE) // size of the index root headers
2364 + 0x18; // Size of dummy key with a VCN for a subnode
2365 ASSERT(MinIndexRootSize.QuadPart % ATTR_RECORD_ALIGNMENT == 0);
2366
2367 // Temporarily shrink the index root to it's minimal size
2368 AttributeLength = MinIndexRootSize.LowPart;
2369 AttributeLength += sizeof(INDEX_ROOT_ATTRIBUTE);
2370
2371
2372 // FIXME: IndexRoot will probably be invalid until we're finished. If we fail before we finish, the directory will probably be toast.
2373 // The potential for catastrophic data-loss exists!!! :)
2374
2375 // Update the length of the attribute in the file record of the parent directory
2377 IndexRootContext,
2378 ParentFileRecord,
2379 IndexRootOffset,
2380 AttributeLength);
2381 if (!NT_SUCCESS(Status))
2382 {
2383 DPRINT1("ERROR: Unable to set length of index root!\n");
2384 DestroyBTree(NewTree);
2385 ReleaseAttributeContext(IndexRootContext);
2386 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2387 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2388 return Status;
2389 }
2390
2391 // Update the index allocation
2392 Status = UpdateIndexAllocation(DeviceExt, NewTree, I30IndexRoot->SizeOfEntry, ParentFileRecord);
2393 if (!NT_SUCCESS(Status))
2394 {
2395 DPRINT1("ERROR: Failed to update index allocation from B-Tree!\n");
2396 DestroyBTree(NewTree);
2397 ReleaseAttributeContext(IndexRootContext);
2398 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2399 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2400 return Status;
2401 }
2402
2403#ifndef NDEBUG
2404 DPRINT1("Index Allocation updated\n");
2405 DumpBTree(NewTree);
2406#endif
2407
2408 // Find the maximum index root size given what the file record can hold
2409 // First, find the max index size assuming index root is the last attribute
2410 NewMaxIndexRootSize =
2411 DeviceExt->NtfsInfo.BytesPerFileRecord // Start with the size of a file record
2412 - IndexRootOffset // Subtract the length of everything that comes before index root
2413 - IndexRootContext->pRecord->Resident.ValueOffset // Subtract the length of the attribute header for index root
2414 - sizeof(INDEX_ROOT_ATTRIBUTE) // Subtract the length of the index root header
2415 - (sizeof(ULONG) * 2); // Subtract the length of the file record end marker and padding
2416
2417 // Are there attributes after this one?
2418 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset + IndexRootContext->pRecord->Length);
2419 if (NextAttribute->Type != AttributeEnd)
2420 {
2421 // Find the length of all attributes after this one, not counting the end marker
2422 ULONG LengthOfAttributes = 0;
2423 PNTFS_ATTR_RECORD CurrentAttribute = NextAttribute;
2424 while (CurrentAttribute->Type != AttributeEnd)
2425 {
2426 LengthOfAttributes += CurrentAttribute->Length;
2427 CurrentAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)CurrentAttribute + CurrentAttribute->Length);
2428 }
2429
2430 // Leave room for the existing attributes
2431 NewMaxIndexRootSize -= LengthOfAttributes;
2432 }
2433
2434 // The index allocation and index bitmap may have grown, leaving less room for the index root,
2435 // so now we need to double-check that index root isn't too large
2436 NodeSize = GetSizeOfIndexEntries(NewTree->RootNode);
2437 if (NodeSize > NewMaxIndexRootSize)
2438 {
2439 DPRINT1("Demoting index root.\nNodeSize: 0x%lx\nNewMaxIndexRootSize: 0x%lx\n", NodeSize, NewMaxIndexRootSize);
2440
2441 Status = DemoteBTreeRoot(NewTree);
2442 if (!NT_SUCCESS(Status))
2443 {
2444 DPRINT1("ERROR: Failed to demote index root!\n");
2445 DestroyBTree(NewTree);
2446 ReleaseAttributeContext(IndexRootContext);
2447 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2448 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2449 return Status;
2450 }
2451
2452 // We need to update the index allocation once more
2453 Status = UpdateIndexAllocation(DeviceExt, NewTree, I30IndexRoot->SizeOfEntry, ParentFileRecord);
2454 if (!NT_SUCCESS(Status))
2455 {
2456 DPRINT1("ERROR: Failed to update index allocation from B-Tree!\n");
2457 DestroyBTree(NewTree);
2458 ReleaseAttributeContext(IndexRootContext);
2459 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2460 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2461 return Status;
2462 }
2463
2464 // re-recalculate max size of index root
2465 NewMaxIndexRootSize =
2466 // Find the maximum index size given what the file record can hold
2467 // First, find the max index size assuming index root is the last attribute
2468 DeviceExt->NtfsInfo.BytesPerFileRecord // Start with the size of a file record
2469 - IndexRootOffset // Subtract the length of everything that comes before index root
2470 - IndexRootContext->pRecord->Resident.ValueOffset // Subtract the length of the attribute header for index root
2471 - sizeof(INDEX_ROOT_ATTRIBUTE) // Subtract the length of the index root header
2472 - (sizeof(ULONG) * 2); // Subtract the length of the file record end marker and padding
2473
2474 // Are there attributes after this one?
2475 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset + IndexRootContext->pRecord->Length);
2476 if (NextAttribute->Type != AttributeEnd)
2477 {
2478 // Find the length of all attributes after this one, not counting the end marker
2479 ULONG LengthOfAttributes = 0;
2480 PNTFS_ATTR_RECORD CurrentAttribute = NextAttribute;
2481 while (CurrentAttribute->Type != AttributeEnd)
2482 {
2483 LengthOfAttributes += CurrentAttribute->Length;
2484 CurrentAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)CurrentAttribute + CurrentAttribute->Length);
2485 }
2486
2487 // Leave room for the existing attributes
2488 NewMaxIndexRootSize -= LengthOfAttributes;
2489 }
2490
2491
2492 }
2493
2494 // Create the Index Root from the B*Tree
2495 Status = CreateIndexRootFromBTree(DeviceExt, NewTree, NewMaxIndexRootSize, &NewIndexRoot, &BtreeIndexLength);
2496 if (!NT_SUCCESS(Status))
2497 {
2498 DPRINT1("ERROR: Failed to create Index root from B-Tree!\n");
2499 DestroyBTree(NewTree);
2500 ReleaseAttributeContext(IndexRootContext);
2501 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2502 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2503 return Status;
2504 }
2505
2506 // We're done with the B-Tree now
2507 DestroyBTree(NewTree);
2508
2509 // Write back the new index root attribute to the parent directory file record
2510
2511 // First, we need to resize the attribute.
2512 // CreateIndexRootFromBTree() should have verified that the index root fits within MaxIndexSize.
2513 // We can't set the size as we normally would, because $INDEX_ROOT must always be resident.
2514 AttributeLength = NewIndexRoot->Header.AllocatedSize + FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header);
2515
2516 if (AttributeLength != IndexRootContext->pRecord->Resident.ValueLength)
2517 {
2518 // Update the length of the attribute in the file record of the parent directory
2520 IndexRootContext,
2521 ParentFileRecord,
2522 IndexRootOffset,
2523 AttributeLength);
2524 if (!NT_SUCCESS(Status))
2525 {
2526 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
2527 ReleaseAttributeContext(IndexRootContext);
2528 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2529 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2530 DPRINT1("ERROR: Unable to set resident attribute length!\n");
2531 return Status;
2532 }
2533
2534 }
2535
2536 NT_ASSERT(ParentFileRecord->BytesInUse <= DeviceExt->NtfsInfo.BytesPerFileRecord);
2537
2538 Status = UpdateFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
2539 if (!NT_SUCCESS(Status))
2540 {
2541 DPRINT1("ERROR: Failed to update file record of directory with index: %llx\n", DirectoryMftIndex);
2542 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2543 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
2544 ReleaseAttributeContext(IndexRootContext);
2545 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2546 return Status;
2547 }
2548
2549 // Write the new index root to disk
2550 Status = WriteAttribute(DeviceExt,
2551 IndexRootContext,
2552 0,
2553 (PUCHAR)NewIndexRoot,
2554 AttributeLength,
2555 &LengthWritten,
2556 ParentFileRecord);
2557 if (!NT_SUCCESS(Status) || LengthWritten != AttributeLength)
2558 {
2559 DPRINT1("ERROR: Unable to write new index root attribute to parent directory!\n");
2560 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
2561 ReleaseAttributeContext(IndexRootContext);
2562 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2563 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2564 return Status;
2565 }
2566
2567 // re-read the parent file record, so we can dump it
2568 Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
2569 if (!NT_SUCCESS(Status))
2570 {
2571 DPRINT1("ERROR: Couldn't read parent directory after messing with it!\n");
2572 }
2573 else
2574 {
2575#ifndef NDEBUG
2576 DPRINT1("Dumping new B-Tree:\n");
2577
2578 Status = CreateBTreeFromIndex(DeviceExt, ParentFileRecord, IndexRootContext, NewIndexRoot, &NewTree);
2579 if (!NT_SUCCESS(Status))
2580 {
2581 DPRINT1("ERROR: Couldn't re-create b-tree\n");
2582 return Status;
2583 }
2584
2585 DumpBTree(NewTree);
2586
2587 DestroyBTree(NewTree);
2588
2589 NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
2590#endif
2591 }
2592
2593 // Cleanup
2594 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
2595 ReleaseAttributeContext(IndexRootContext);
2596 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2597 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2598
2599 return Status;
2600}
NTSTATUS CreateBTreeFromIndex(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecordWithIndex, PNTFS_ATTR_CONTEXT IndexRootContext, PINDEX_ROOT_ATTRIBUTE IndexRoot, PB_TREE *NewTree)
Definition: btree.c:682
NTSTATUS NtfsInsertKey(PB_TREE Tree, ULONGLONG FileReference, PFILENAME_ATTRIBUTE FileNameAttribute, PB_TREE_FILENAME_NODE Node, BOOLEAN CaseSensitive, ULONG MaxIndexRootSize, ULONG IndexRecordSize, PB_TREE_KEY *MedianKey, PB_TREE_FILENAME_NODE *NewRightHandSibling)
Definition: btree.c:1691
NTSTATUS UpdateIndexAllocation(PDEVICE_EXTENSION DeviceExt, PB_TREE Tree, ULONG IndexBufferSize, PFILE_RECORD_HEADER FileRecord)
Definition: btree.c:1182
NTSTATUS DemoteBTreeRoot(PB_TREE Tree)
Definition: btree.c:1089
ULONG GetSizeOfIndexEntries(PB_TREE_FILENAME_NODE Node)
Definition: btree.c:855
NTSTATUS CreateIndexRootFromBTree(PDEVICE_EXTENSION DeviceExt, PB_TREE Tree, ULONG MaxIndexSize, PINDEX_ROOT_ATTRIBUTE *IndexRoot, ULONG *Length)
Definition: btree.c:910
VOID NtfsDumpFileRecord(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:3334
NTSTATUS InternalSetResidentAttributeLength(PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_CONTEXT AttrContext, PFILE_RECORD_HEADER FileRecord, ULONG AttrOffset, ULONG DataSize)
Definition: mft.c:542
PB_TREE_FILENAME_NODE RootNode
Definition: ntfs.h:455

Referenced by NtfsCreateDirectory(), and NtfsCreateFileRecord().

◆ NtfsAllocateClusters()

NTSTATUS NtfsAllocateClusters ( PDEVICE_EXTENSION  DeviceExt,
ULONG  FirstDesiredCluster,
ULONG  DesiredClusters,
PULONG  FirstAssignedCluster,
PULONG  AssignedClusters 
)

NtfsAllocateClusters Allocates a run of clusters. The run allocated might be smaller than DesiredClusters.

Definition at line 105 of file volinfo.c.

110{
112 PFILE_RECORD_HEADER BitmapRecord;
113 PNTFS_ATTR_CONTEXT DataContext;
114 ULONGLONG BitmapDataSize;
118 ULONG AssignedRun;
119 ULONG LengthWritten;
120
121 DPRINT("NtfsAllocateClusters(%p, %lu, %lu, %p, %p)\n", DeviceExt, FirstDesiredCluster, DesiredClusters, FirstAssignedCluster, AssignedClusters);
122
123 BitmapRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
124 if (BitmapRecord == NULL)
125 {
127 }
128
129 Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord);
130 if (!NT_SUCCESS(Status))
131 {
132 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
133 return Status;
134 }
135
136 Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL);
137 if (!NT_SUCCESS(Status))
138 {
139 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
140 return Status;
141 }
142
143 BitmapDataSize = AttributeDataLength(DataContext->pRecord);
144 BitmapDataSize = min(BitmapDataSize, 0xffffffff);
145 ASSERT((BitmapDataSize * 8) >= DeviceExt->NtfsInfo.ClusterCount);
146 BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS);
147 if (BitmapData == NULL)
148 {
149 ReleaseAttributeContext(DataContext);
150 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
152 }
153
154 DPRINT("Total clusters: %I64x\n", DeviceExt->NtfsInfo.ClusterCount);
155 DPRINT("Total clusters in bitmap: %I64x\n", BitmapDataSize * 8);
156 DPRINT("Diff in size: %I64d B\n", ((BitmapDataSize * 8) - DeviceExt->NtfsInfo.ClusterCount) * DeviceExt->NtfsInfo.SectorsPerCluster * DeviceExt->NtfsInfo.BytesPerSector);
157
158 ReadAttribute(DeviceExt, DataContext, 0, (PCHAR)BitmapData, (ULONG)BitmapDataSize);
159
160 RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.ClusterCount);
162
163 if (FreeClusters < DesiredClusters)
164 {
165 ReleaseAttributeContext(DataContext);
166
168 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
169 return STATUS_DISK_FULL;
170 }
171
172 // TODO: Observe MFT reservation zone
173
174 // Can we get one contiguous run?
175 AssignedRun = RtlFindClearBitsAndSet(&Bitmap, DesiredClusters, FirstDesiredCluster);
176
177 if (AssignedRun != 0xFFFFFFFF)
178 {
179 *FirstAssignedCluster = AssignedRun;
180 *AssignedClusters = DesiredClusters;
181 }
182 else
183 {
184 // we can't get one contiguous run
185 *AssignedClusters = RtlFindNextForwardRunClear(&Bitmap, FirstDesiredCluster, FirstAssignedCluster);
186
187 if (*AssignedClusters == 0)
188 {
189 // we couldn't find any runs starting at DesiredFirstCluster
190 *AssignedClusters = RtlFindLongestRunClear(&Bitmap, FirstAssignedCluster);
191 }
192
193 }
194
195 Status = WriteAttribute(DeviceExt, DataContext, 0, BitmapData, (ULONG)BitmapDataSize, &LengthWritten, BitmapRecord);
196
197 ReleaseAttributeContext(DataContext);
198