ReactOS 0.4.15-dev-7953-g1f49173
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 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 STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#define Vcb
Definition: cdprocs.h:1415
#define STATUS_SUCCESS
Definition: shellext.h:65
UCHAR Reserved
Definition: ntfs.h:141
ULONG Length
Definition: ntfs.h:127
USHORT NameOffset
Definition: ntfs.h:130
USHORT Instance
Definition: ntfs.h:132
struct NTFS_ATTR_RECORD::@175::@177 Resident
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:32
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:71
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::@175::@178 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}
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
NTSYSAPI void WINAPI RtlInitializeBitMap(PRTL_BITMAP, PULONG, ULONG)
NTSYSAPI ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP, ULONG, ULONG)
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 _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
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:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#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:896
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:3287

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:3310

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 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: limits.h:44
NTSYSAPI void WINAPI RtlClearBits(PRTL_BITMAP, ULONG, ULONG)
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
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260

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:3004
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:383

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: debug.h:115
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
_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
200 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
201
202 return Status;
203}
NTSTATUS FreeClusters(PNTFS_VCB Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, ULONG ClustersToFree)
Definition: attrib.c:1057
NTSYSAPI ULONG WINAPI RtlFindLongestRunClear(PCRTL_BITMAP, PULONG)
NTSYSAPI ULONG WINAPI RtlNumberOfClearBits(PCRTL_BITMAP)
NTSYSAPI ULONG WINAPI RtlFindNextForwardRunClear(PCRTL_BITMAP, ULONG, PULONG)
#define STATUS_DISK_FULL
Definition: udferr_usr.h:155

Referenced by SetNonResidentAttributeDataLength().

◆ NtfsAllocateIrpContext()

PNTFS_IRP_CONTEXT NtfsAllocateIrpContext ( PDEVICE_OBJECT  DeviceObject,
PIRP  Irp 
)

Definition at line 66 of file misc.c.

68{
69 PNTFS_IRP_CONTEXT IrpContext;
70
71 TRACE_(NTFS, "NtfsAllocateIrpContext()\n");
72
73 IrpContext = (PNTFS_IRP_CONTEXT)ExAllocateFromNPagedLookasideList(&NtfsGlobalData->IrpContextLookasideList);
74 if (IrpContext == NULL)
75 return NULL;
76
77 RtlZeroMemory(IrpContext, sizeof(NTFS_IRP_CONTEXT));
78
80 IrpContext->Identifier.Size = sizeof(NTFS_IRP_CONTEXT);
81 IrpContext->Irp = Irp;
82 IrpContext->DeviceObject = DeviceObject;
84 IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
85 IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
86 IrpContext->FileObject = IrpContext->Stack->FileObject;
87 IrpContext->IsTopLevel = (IoGetTopLevelIrp() == Irp);
88 IrpContext->PriorityBoost = IO_NO_INCREMENT;
89 IrpContext->Flags = IRPCONTEXT_COMPLETE;
90
91 if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
92 IrpContext->MajorFunction == IRP_MJ_DEVICE_CONTROL ||
93 IrpContext->MajorFunction == IRP_MJ_SHUTDOWN ||
94 (IrpContext->MajorFunction != IRP_MJ_CLEANUP &&
95 IrpContext->MajorFunction != IRP_MJ_CLOSE &&
97 {
98 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
99 }
100
101 return IrpContext;
102}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
_In_ PIRP Irp
Definition: csq.h:116
#define TRACE_(x)
Definition: compat.h:76
#define IRPCONTEXT_COMPLETE
Definition: ntfs.h:475
struct NTFS_IRP_CONTEXT * PNTFS_IRP_CONTEXT
#define IRPCONTEXT_CANWAIT
Definition: ntfs.h:474
#define NTFS_TYPE_IRP_CONTEXT
Definition: ntfs.h:90
BOOLEAN NTAPI IoIsOperationSynchronous(IN PIRP Irp)
Definition: irp.c:1882
PIRP NTAPI IoGetTopLevelIrp(VOID)
Definition: irp.c:1843
#define IRP_MJ_CLOSE
Definition: rdpdr.c:45
#define IRP_MJ_DEVICE_CONTROL
Definition: rdpdr.c:52
ULONG Type
Definition: ntfs.h:95
ULONG Size
Definition: ntfs.h:96
NPAGED_LOOKASIDE_LIST IrpContextLookasideList
Definition: ntfs.h:152
NTFSIDENTIFIER Identifier
Definition: ntfs.h:480
PFILE_OBJECT FileObject
Definition: ntfs.h:489
UCHAR MajorFunction
Definition: ntfs.h:483
ULONG Flags
Definition: ntfs.h:481
PIO_STACK_LOCATION Stack
Definition: ntfs.h:482
UCHAR MinorFunction
Definition: ntfs.h:484
CCHAR PriorityBoost
Definition: ntfs.h:491
BOOLEAN IsTopLevel
Definition: ntfs.h:487
PDEVICE_OBJECT DeviceObject
Definition: ntfs.h:488
PFILE_OBJECT FileObject
Definition: iotypes.h:3169
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#define IRP_MJ_FILE_SYSTEM_CONTROL
#define IRP_MJ_SHUTDOWN
#define IRP_MJ_CLEANUP

Referenced by NtfsFsdDispatch().

◆ NtfsAttachFCBToFileObject()

NTSTATUS NtfsAttachFCBToFileObject ( PNTFS_VCB  Vcb,
PNTFS_FCB  Fcb,
PFILE_OBJECT  FileObject 
)

Definition at line 464 of file fcb.c.

467{
468 PNTFS_CCB newCCB;
469
471 if (newCCB == NULL)
472 {
474 }
475
476 RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
477
478 newCCB->Identifier.Type = NTFS_TYPE_CCB;
479 newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
480
481 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
482 FileObject->FsContext = Fcb;
483 FileObject->FsContext2 = newCCB;
484 newCCB->PtrFileObject = FileObject;
485 Fcb->Vcb = Vcb;
486
488 {
490 {
493 FALSE,
495 Fcb);
496 }
498 {
499 FileObject->FsContext2 = NULL;
500 ExFreePoolWithTag(newCCB, TAG_CCB);
501 return _SEH2_GetExceptionCode();
502 }
503 _SEH2_END;
504
506 }
507
508 //DPRINT("file open: fcb:%x file size: %d\n", Fcb, Fcb->Entry.DataLengthL);
509
510 return STATUS_SUCCESS;
511}
#define TAG_CCB
Definition: cdprocs.h:85
#define FCB_CACHE_INITIALIZED
Definition: ntfs.h:508
#define NTFS_TYPE_CCB
Definition: ntfs.h:87
VOID NTAPI CcInitializeCacheMap(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes, IN BOOLEAN PinAccess, IN PCACHE_MANAGER_CALLBACKS Callbacks, IN PVOID LazyWriteContext)
Definition: fssup.c:195
Definition: ntfs.h:130
PFILE_OBJECT PtrFileObject
Definition: ntfs.h:133
NTFSIDENTIFIER Identifier
Definition: ntfs.h:131
CACHE_MANAGER_CALLBACKS CacheMgrCallbacks
Definition: ntfs.h:149
ULONG Flags
Definition: ntfs.h:536
FSRTL_COMMON_FCB_HEADER RFCB
Definition: ntfs.h:517
SECTION_OBJECT_POINTERS SectionObjectPointers
Definition: ntfs.h:518
LARGE_INTEGER AllocationSize
Definition: env_spec_w32.h:755

Referenced by NtfsCreateFile(), NtfsOpenFile(), and NtfsOpenFileById().

◆ NtfsCleanup()

NTSTATUS NtfsCleanup ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 89 of file cleanup.c.

90{
91 PDEVICE_EXTENSION DeviceExtension;
95
96 DPRINT("NtfsCleanup() called\n");
97
98 DeviceObject = IrpContext->DeviceObject;
100 {
101 DPRINT("Cleaning up file system\n");
102 IrpContext->Irp->IoStatus.Information = 0;
103 return STATUS_SUCCESS;
104 }
105
106 FileObject = IrpContext->FileObject;
107 DeviceExtension = DeviceObject->DeviceExtension;
108
109 if (!ExAcquireResourceExclusiveLite(&DeviceExtension->DirResource,
111 {
112 return NtfsMarkIrpContextForQueue(IrpContext);
113 }
114
115 Status = NtfsCleanupFile(DeviceExtension, FileObject, BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT));
116
117 ExReleaseResourceLite(&DeviceExtension->DirResource);
118
119 if (Status == STATUS_PENDING)
120 {
121 return NtfsMarkIrpContextForQueue(IrpContext);
122 }
123
124 IrpContext->Irp->IoStatus.Information = 0;
125 return Status;
126}
NTSTATUS NtfsCleanupFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, BOOLEAN CanWait)
Definition: cleanup.c:40
FORCEINLINE NTSTATUS NtfsMarkIrpContextForQueue(PNTFS_IRP_CONTEXT IrpContext)
Definition: ntfs.h:569
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
#define STATUS_PENDING
Definition: ntstatus.h:82
PDEVICE_OBJECT DeviceObject
Definition: ntfs.h:148
IO_STATUS_BLOCK IoStatus
* PFILE_OBJECT
Definition: iotypes.h:1998

Referenced by NtfsDispatch().

◆ NtfsClose()

NTSTATUS NtfsClose ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 84 of file close.c.

85{
86 PDEVICE_EXTENSION DeviceExtension;
90
91 DPRINT("NtfsClose() called\n");
92
93 DeviceObject = IrpContext->DeviceObject;
95 {
96 DPRINT("Closing file system\n");
97 IrpContext->Irp->IoStatus.Information = 0;
98 return STATUS_SUCCESS;
99 }
100
101 FileObject = IrpContext->FileObject;
102 DeviceExtension = DeviceObject->DeviceExtension;
103
104 if (!ExAcquireResourceExclusiveLite(&DeviceExtension->DirResource,
106 {
107 return NtfsMarkIrpContextForQueue(IrpContext);
108 }
109
110 Status = NtfsCloseFile(DeviceExtension, FileObject);
111
112 ExReleaseResourceLite(&DeviceExtension->DirResource);
113
114 if (Status == STATUS_PENDING)
115 {
116 return NtfsMarkIrpContextForQueue(IrpContext);
117 }
118
119 IrpContext->Irp->IoStatus.Information = 0;
120 return Status;
121}
NTSTATUS NtfsCloseFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
Definition: close.c:40

◆ NtfsCloseFile()

NTSTATUS NtfsCloseFile ( PDEVICE_EXTENSION  DeviceExt,
PFILE_OBJECT  FileObject 
)

Definition at line 40 of file close.c.

42{
45
46 DPRINT("NtfsCloseFile(DeviceExt %p, FileObject %p)\n",
47 DeviceExt,
49
50 Ccb = (PNTFS_CCB)(FileObject->FsContext2);
51 Fcb = (PNTFS_FCB)(FileObject->FsContext);
52
53 DPRINT("Ccb %p\n", Ccb);
54 if (Ccb == NULL)
55 {
56 return STATUS_SUCCESS;
57 }
58
59 FileObject->FsContext2 = NULL;
60 FileObject->FsContext = NULL;
61 FileObject->SectionObjectPointer = NULL;
62 DeviceExt->OpenHandleCount--;
63
64 if (FileObject->FileName.Buffer)
65 {
66 // This a FO, that was created outside from FSD.
67 // Some FO's are created with IoCreateStreamFileObject() insid from FSD.
68 // This FO's don't have a FileName.
69 NtfsReleaseFCB(DeviceExt, Fcb);
70 }
71
72 if (Ccb->DirectorySearchPattern)
73 {
74 ExFreePool(Ccb->DirectorySearchPattern);
75 }
76
78
79 return STATUS_SUCCESS;
80}
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:592
struct NTFS_CCB * PNTFS_CCB
struct _FCB * PNTFS_FCB
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
VOID NtfsReleaseFCB(PNTFS_VCB Vcb, PNTFS_FCB Fcb)
Definition: fcb.c:182
Definition: cdstruc.h:902

Referenced by NtfsClose(), and NtfsCreateFile().

◆ NtfsCreate()

NTSTATUS NtfsCreate ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 622 of file create.c.

623{
624 PDEVICE_EXTENSION DeviceExt;
627
628 DeviceObject = IrpContext->DeviceObject;
630 {
631 /* DeviceObject represents FileSystem instead of logical volume */
632 DPRINT("Opening file system\n");
633 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
634 return STATUS_SUCCESS;
635 }
636
637 DeviceExt = DeviceObject->DeviceExtension;
638
639 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
640 {
641 return NtfsMarkIrpContextForQueue(IrpContext);
642 }
643
644 ExAcquireResourceExclusiveLite(&DeviceExt->DirResource,
645 TRUE);
647 IrpContext);
648 ExReleaseResourceLite(&DeviceExt->DirResource);
649
650 return Status;
651}
static NTSTATUS NtfsCreateFile(PDEVICE_OBJECT DeviceObject, PNTFS_IRP_CONTEXT IrpContext)
Definition: create.c:328
#define FILE_OPENED
Definition: nt_native.h:769

Referenced by NtfsDispatch().

◆ NtfsCreateDirectory()

NTSTATUS NtfsCreateDirectory ( PDEVICE_EXTENSION  DeviceExt,
PFILE_OBJECT  FileObject,
BOOLEAN  CaseSensitive,
BOOLEAN  CanWait 
)

Definition at line 681 of file create.c.

685{
686
688 PFILE_RECORD_HEADER FileRecord;
689 PNTFS_ATTR_RECORD NextAttribute;
690 PFILENAME_ATTRIBUTE FilenameAttribute;
691 ULONGLONG ParentMftIndex;
692 ULONGLONG FileMftIndex;
694 PINDEX_ROOT_ATTRIBUTE NewIndexRoot;
695 ULONG MaxIndexRootSize;
696 ULONG RootLength;
697
698 DPRINT("NtfsCreateFileRecord(%p, %p, %s, %s)\n",
699 DeviceExt,
701 CaseSensitive ? "TRUE" : "FALSE",
702 CanWait ? "TRUE" : "FALSE");
703
704 // Start with an empty file record
705 FileRecord = NtfsCreateEmptyFileRecord(DeviceExt);
706 if (!FileRecord)
707 {
708 DPRINT1("ERROR: Unable to allocate memory for file record!\n");
710 }
711
712 // Set the directory flag
713 FileRecord->Flags |= FRH_DIRECTORY;
714
715 // find where the first attribute will be added
716 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
717
718 // add first attribute, $STANDARD_INFORMATION
719 AddStandardInformation(FileRecord, NextAttribute);
720
721 // advance NextAttribute pointer to the next attribute
722 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
723
724 // Add the $FILE_NAME attribute
725 AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject, CaseSensitive, &ParentMftIndex);
726
727 // save a pointer to the filename attribute
728 FilenameAttribute = (PFILENAME_ATTRIBUTE)((ULONG_PTR)NextAttribute + NextAttribute->Resident.ValueOffset);
729
730 // advance NextAttribute pointer to the next attribute
731 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
732
733 // Create an empty b-tree to represent our new index
735 if (!NT_SUCCESS(Status))
736 {
737 DPRINT1("ERROR: Failed to create empty B-Tree!\n");
738 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
739 return Status;
740 }
741
742 // Calculate maximum size of index root
743 MaxIndexRootSize = DeviceExt->NtfsInfo.BytesPerFileRecord
744 - ((ULONG_PTR)NextAttribute - (ULONG_PTR)FileRecord)
745 - sizeof(ULONG) * 2;
746
747 // Create a new index record from the tree
749 Tree,
750 MaxIndexRootSize,
751 &NewIndexRoot,
752 &RootLength);
753 if (!NT_SUCCESS(Status))
754 {
755 DPRINT1("ERROR: Unable to create empty index root!\n");
757 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
758 return Status;
759 }
760
761 // We're done with the B-Tree
763
764 // add the $INDEX_ROOT attribute
765 Status = AddIndexRoot(DeviceExt, FileRecord, NextAttribute, NewIndexRoot, RootLength, L"$I30", 4);
766 if (!NT_SUCCESS(Status))
767 {
768 DPRINT1("ERROR: Failed to add index root to new file record!\n");
769 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
770 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
771 return Status;
772 }
773
774
775#ifndef NDEBUG
776 NtfsDumpFileRecord(DeviceExt, FileRecord);
777#endif
778
779 // Now that we've built the file record in memory, we need to store it in the MFT.
780 Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex, CanWait);
781 if (NT_SUCCESS(Status))
782 {
783 // The highest 2 bytes should be the sequence number, unless the parent happens to be root
784 if (FileMftIndex == NTFS_FILE_ROOT)
785 FileMftIndex = FileMftIndex + ((ULONGLONG)NTFS_FILE_ROOT << 48);
786 else
787 FileMftIndex = FileMftIndex + ((ULONGLONG)FileRecord->SequenceNumber << 48);
788
789 DPRINT1("New File Reference: 0x%016I64x\n", FileMftIndex);
790
791 // Add the filename attribute to the filename-index of the parent directory
793 ParentMftIndex,
794 FileMftIndex,
795 FilenameAttribute,
796 CaseSensitive);
797 }
798
799 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
800 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
801
802 return Status;
803}
NTSTATUS CreateEmptyBTree(PB_TREE *NewTree)
Definition: btree.c:348
NTSTATUS AddIndexRoot(PNTFS_VCB Vcb, PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress, PINDEX_ROOT_ATTRIBUTE NewIndexRoot, ULONG RootLength, PCWSTR Name, USHORT NameLength)
Definition: attrib.c:495
NTSTATUS AddFileName(PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress, PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, BOOLEAN CaseSensitive, PULONGLONG ParentMftIndex)
Definition: attrib.c:230
NTSTATUS AddStandardInformation(PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress)
Definition: attrib.c:766
PFILE_RECORD_HEADER NtfsCreateEmptyFileRecord(PDEVICE_EXTENSION DeviceExt)
Definition: create.c:818
NTSTATUS NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt, ULONGLONG DirectoryMftIndex, ULONGLONG FileReferenceNumber, PFILENAME_ATTRIBUTE FilenameAttribute, BOOLEAN CaseSensitive)
Definition: mft.c:2192

Referenced by NtfsCreateFile().

◆ NtfsCreateEmptyFileRecord()

PFILE_RECORD_HEADER NtfsCreateEmptyFileRecord ( PDEVICE_EXTENSION  DeviceExt)

Definition at line 818 of file create.c.

819{
820 PFILE_RECORD_HEADER FileRecord;
821 PNTFS_ATTR_RECORD NextAttribute;
822
823 DPRINT("NtfsCreateEmptyFileRecord(%p)\n", DeviceExt);
824
825 // allocate memory for file record
826 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
827 if (!FileRecord)
828 {
829 DPRINT1("ERROR: Unable to allocate memory for file record!\n");
830 return NULL;
831 }
832
833 RtlZeroMemory(FileRecord, DeviceExt->NtfsInfo.BytesPerFileRecord);
834
835 FileRecord->Ntfs.Type = NRH_FILE_TYPE;
836
837 // calculate USA offset and count
838 FileRecord->Ntfs.UsaOffset = FIELD_OFFSET(FILE_RECORD_HEADER, MFTRecordNumber) + sizeof(ULONG);
839
840 // size of USA (in ULONG's) will be 1 (for USA number) + 1 for every sector the file record uses
841 FileRecord->BytesAllocated = DeviceExt->NtfsInfo.BytesPerFileRecord;
842 FileRecord->Ntfs.UsaCount = (FileRecord->BytesAllocated / DeviceExt->NtfsInfo.BytesPerSector) + 1;
843
844 // setup other file record fields
845 FileRecord->SequenceNumber = 1;
846 FileRecord->AttributeOffset = FileRecord->Ntfs.UsaOffset + (2 * FileRecord->Ntfs.UsaCount);
848 FileRecord->Flags = FRH_IN_USE;
849 FileRecord->BytesInUse = FileRecord->AttributeOffset + sizeof(ULONG) * 2;
850
851 // find where the first attribute will be added
852 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
853
854 // mark the (temporary) end of the file-record
855 NextAttribute->Type = AttributeEnd;
856 NextAttribute->Length = FILE_RECORD_END;
857
858 return FileRecord;
859}
#define NRH_FILE_TYPE
Definition: ntfs.h:246
#define FRH_IN_USE
Definition: ntfs.h:267
USHORT UsaCount
Definition: ntfs.h:241
USHORT UsaOffset
Definition: ntfs.h:240
NTFS_RECORD_HEADER Ntfs
Definition: ntfs.h:252
ULONG BytesAllocated
Definition: ntfs.h:258

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

◆ NtfsCreateFCB()

PNTFS_FCB NtfsCreateFCB ( PCWSTR  FileName,
PCWSTR  Stream,
PNTFS_VCB  Vcb 
)

Definition at line 67 of file fcb.c.

70{
72
73 ASSERT(Vcb);
74 ASSERT(Vcb->Identifier.Type == NTFS_TYPE_VCB);
75
76 Fcb = ExAllocateFromNPagedLookasideList(&NtfsGlobalData->FcbLookasideList);
77 if (Fcb == NULL)
78 {
79 return NULL;
80 }
81
82 RtlZeroMemory(Fcb, sizeof(NTFS_FCB));
83
86
87 Fcb->Vcb = Vcb;
88
89 if (FileName)
90 {
92 if (wcsrchr(Fcb->PathName, '\\') != 0)
93 {
95 }
96 else
97 {
99 }
100 }
101
102 if (Stream)
103 {
105 }
106 else
107 {
108 Fcb->Stream[0] = UNICODE_NULL;
109 }
110
112
114
115 return Fcb;
116}
#define wcsrchr
Definition: compat.h:16
#define NTFS_TYPE_VCB
Definition: ntfs.h:89
#define NTFS_TYPE_FCB
Definition: ntfs.h:88
NTSTATUS ExInitializeResourceLite(PULONG res)
Definition: env_spec_w32.h:641
static IStream Stream
Definition: htmldoc.c:1115
#define UNICODE_NULL
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
NPAGED_LOOKASIDE_LIST FcbLookasideList
Definition: ntfs.h:153
WCHAR Stream[MAX_PATH]
Definition: ntfs.h:523
NTFSIDENTIFIER Identifier
Definition: ntfs.h:515
WCHAR * ObjectName
Definition: ntfs.h:524
WCHAR PathName[MAX_PATH]
Definition: ntfs.h:525
ERESOURCE MainResource
Definition: ntfs.h:528

Referenced by NtfsGetVolumeData(), NtfsMakeFCBFromDirEntry(), NtfsMakeRootFCB(), and NtfsMountVolume().

◆ NtfsCreateFileRecord()

NTSTATUS NtfsCreateFileRecord ( PDEVICE_EXTENSION  DeviceExt,
PFILE_OBJECT  FileObject,
BOOLEAN  CaseSensitive,
BOOLEAN  CanWait 
)

Definition at line 886 of file create.c.

890{
892 PFILE_RECORD_HEADER FileRecord;
893 PNTFS_ATTR_RECORD NextAttribute;
894 PFILENAME_ATTRIBUTE FilenameAttribute;
895 ULONGLONG ParentMftIndex;
896 ULONGLONG FileMftIndex;
897
898 DPRINT("NtfsCreateFileRecord(%p, %p, %s, %s)\n",
899 DeviceExt,
901 CaseSensitive ? "TRUE" : "FALSE",
902 CanWait ? "TRUE" : "FALSE");
903
904 // allocate memory for file record
905 FileRecord = NtfsCreateEmptyFileRecord(DeviceExt);
906 if (!FileRecord)
907 {
908 DPRINT1("ERROR: Unable to allocate memory for file record!\n");
910 }
911
912 // find where the first attribute will be added
913 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
914
915 // add first attribute, $STANDARD_INFORMATION
916 AddStandardInformation(FileRecord, NextAttribute);
917
918 // advance NextAttribute pointer to the next attribute
919 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
920
921 // Add the $FILE_NAME attribute
922 AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject, CaseSensitive, &ParentMftIndex);
923
924 // save a pointer to the filename attribute
925 FilenameAttribute = (PFILENAME_ATTRIBUTE)((ULONG_PTR)NextAttribute + NextAttribute->Resident.ValueOffset);
926
927 // advance NextAttribute pointer to the next attribute
928 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
929
930 // add the $DATA attribute
931 AddData(FileRecord, NextAttribute);
932
933#ifndef NDEBUG
934 // dump file record in memory (for debugging)
935 NtfsDumpFileRecord(DeviceExt, FileRecord);
936#endif
937
938 // Now that we've built the file record in memory, we need to store it in the MFT.
939 Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex, CanWait);
940 if (NT_SUCCESS(Status))
941 {
942 // The highest 2 bytes should be the sequence number, unless the parent happens to be root
943 if (FileMftIndex == NTFS_FILE_ROOT)
944 FileMftIndex = FileMftIndex + ((ULONGLONG)NTFS_FILE_ROOT << 48);
945 else
946 FileMftIndex = FileMftIndex + ((ULONGLONG)FileRecord->SequenceNumber << 48);
947
948 DPRINT1("New File Reference: 0x%016I64x\n", FileMftIndex);
949
950 // Add the filename attribute to the filename-index of the parent directory
952 ParentMftIndex,
953 FileMftIndex,
954 FilenameAttribute,
955 CaseSensitive);
956 }
957
958 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
959
960 return Status;
961}
NTSTATUS AddData(PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress)
Definition: attrib.c:160

Referenced by NtfsCreateFile().

◆ NtfsDestroyFCB()

VOID NtfsDestroyFCB ( PNTFS_FCB  Fcb)

Definition at line 120 of file fcb.c.

121{
122 ASSERT(Fcb);
124
126
127 ExFreeToNPagedLookasideList(&NtfsGlobalData->FcbLookasideList, Fcb);
128}
#define ExDeleteResourceLite(res)
Definition: env_spec_w32.h:647

Referenced by NtfsReleaseFCB().

◆ NtfsDeviceControl()

NTSTATUS NtfsDeviceControl ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 36 of file devctl.c.

37{
38 PDEVICE_EXTENSION DeviceExt;
39 PIRP Irp = IrpContext->Irp;
40
41 DeviceExt = IrpContext->DeviceObject->DeviceExtension;
43
44 /* Lower driver will complete - we don't have to */
45 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
46
47 return IoCallDriver(DeviceExt->StorageDevice, Irp);
48}
#define IoSkipCurrentIrpStackLocation(Irp)
Definition: ntifs_ex.h:421
#define IoCallDriver
Definition: irp.c:1225
PVOID DeviceExtension
Definition: env_spec_w32.h:418

Referenced by NtfsDispatch().

◆ NtfsDeviceIoControl()

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 
)

Definition at line 326 of file blockdev.c.

333{
337 PIRP Irp;
339
341
342 DPRINT("Building device I/O control request ...\n");
346 InputBufferSize,
348 (OutputBufferSize) ? *OutputBufferSize : 0,
349 FALSE,
350 &Event,
351 &IoStatus);
352 if (Irp == NULL)
353 {
354 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
356 }
357
358 if (Override)
359 {
362 }
363
364 DPRINT("Calling IO Driver... with irp %p\n", Irp);
366 if (Status == STATUS_PENDING)
367 {
369 Status = IoStatus.Status;
370 }
371
372 if (OutputBufferSize)
373 {
374 *OutputBufferSize = IoStatus.Information;
375 }
376
377 return Status;
378}
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
__in UCHAR __in POWER_STATE __in_opt PVOID __in PIO_STATUS_BLOCK IoStatus
Definition: mxum.h:159
#define KernelMode
Definition: asm.h:34
@ NotificationEvent
PIRP NTAPI IoBuildDeviceIoControlRequest(IN ULONG IoControlCode, IN PDEVICE_OBJECT DeviceObject, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength, IN BOOLEAN InternalDeviceIoControl, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock)
Definition: irp.c:881
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR OutputBuffer
Definition: wdfiotarget.h:863
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR InputBuffer
Definition: wdfiotarget.h:953
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
_IRQL_requires_same_ typedef _In_ ULONG ControlCode
Definition: wmitypes.h:55
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2695
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1823
@ Suspended
Definition: ketypes.h:420

Referenced by NtfsGetVolumeData(), and NtfsHasFileSystem().

◆ NtfsDirectoryControl()

NTSTATUS NtfsDirectoryControl ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 590 of file dirctl.c.

591{
593
594 DPRINT("NtfsDirectoryControl() called\n");
595
596 switch (IrpContext->MinorFunction)
597 {
599 Status = NtfsQueryDirectory(IrpContext);
600 break;
601
603 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
605 break;
606
607 default:
609 break;
610 }
611
612 if (Status == STATUS_PENDING && IrpContext->Flags & IRPCONTEXT_COMPLETE)
613 {
614 return NtfsMarkIrpContextForQueue(IrpContext);
615 }
616
617 IrpContext->Irp->IoStatus.Information = 0;
618
619 return Status;
620}
NTSTATUS NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
Definition: dirctl.c:359
#define IRP_MN_QUERY_DIRECTORY
Definition: rdpdr.c:55
#define IRP_MN_NOTIFY_CHANGE_DIRECTORY
Definition: rdpdr.c:56
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138

Referenced by NtfsDispatch().

◆ NtfsDumpData()

VOID NtfsDumpData ( ULONG_PTR  Buffer,
ULONG  Length 
)

Definition at line 3297 of file mft.c.

3298{
3299 ULONG i, j;
3300
3301 // dump binary data, 8 bytes at a time
3302 for (i = 0; i < Length; i += 8)
3303 {
3304 // display current offset, in hex
3305 DbgPrint("\t%03x\t", i);
3306
3307 // display hex value of each of the next 8 bytes
3308 for (j = 0; j < 8; j++)
3309 DbgPrint("%02x ", *(PUCHAR)(Buffer + i + j));
3310 DbgPrint("\n");
3311 }
3312}
Definition: bufpool.h:45
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 GLint GLint j
Definition: glfuncs.h:250

◆ NtfsDumpDataRuns()

VOID NtfsDumpDataRuns ( PVOID  StartOfRun,
ULONGLONG  CurrentLCN 
)

Definition at line 1755 of file attrib.c.

1757{
1758 PUCHAR DataRun = StartOfRun;
1759 LONGLONG DataRunOffset;
1760 ULONGLONG DataRunLength;
1761
1762 if (CurrentLCN == 0)
1763 {
1764 DPRINT1("Dumping data runs.\n\tData:\n\t\t");
1765 NtfsDumpDataRunData(StartOfRun);
1766 DbgPrint("\n\tRuns:\n\t\tOff\t\tLCN\t\tLength\n");
1767 }
1768
1769 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1770
1771 if (DataRunOffset != -1)
1772 CurrentLCN += DataRunOffset;
1773
1774 DbgPrint("\t\t%I64d\t", DataRunOffset);
1775 if (DataRunOffset < 99999)
1776 DbgPrint("\t");
1777 DbgPrint("%I64u\t", CurrentLCN);
1778 if (CurrentLCN < 99999)
1779 DbgPrint("\t");
1780 DbgPrint("%I64u\n", DataRunLength);
1781
1782 if (*DataRun == 0)
1783 DbgPrint("\t\t00\n");
1784 else
1785 NtfsDumpDataRuns(DataRun, CurrentLCN);
1786}
VOID NtfsDumpDataRunData(PUCHAR DataRun)
Definition: attrib.c:1723

Referenced by AddRun(), FreeClusters(), and NtfsDumpDataRuns().

◆ NtfsDumpFileAttributes()

VOID NtfsDumpFileAttributes ( PDEVICE_EXTENSION  Vcb,
PFILE_RECORD_HEADER  FileRecord 
)

Definition at line 1790 of file attrib.c.

1792{
1795 PNTFS_ATTR_RECORD Attribute;
1796
1797 Status = FindFirstAttribute(&Context, Vcb, FileRecord, FALSE, &Attribute);
1798 while (NT_SUCCESS(Status))
1799 {
1800 NtfsDumpAttribute(Vcb, Attribute);
1801
1802 Status = FindNextAttribute(&Context, &Attribute);
1803 }
1804
1806}
static VOID NtfsDumpAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_RECORD Attribute)
Definition: attrib.c:1617

Referenced by IncreaseMftSize(), NtfsDumpFileRecord(), NtfsGetBothDirectoryInformation(), NtfsGetDirectoryInformation(), NtfsGetFullDirectoryInformation(), NtfsGetNamesInformation(), and NtfsGetVolumeData().

◆ NtfsDumpFileRecord()

VOID NtfsDumpFileRecord ( PDEVICE_EXTENSION  Vcb,
PFILE_RECORD_HEADER  FileRecord 
)

Definition at line 3334 of file mft.c.

3336{
3337 ULONG i, j;
3338
3339 // dump binary data, 8 bytes at a time
3340 for (i = 0; i < FileRecord->BytesInUse; i += 8)
3341 {
3342 // display current offset, in hex
3343 DbgPrint("\t%03x\t", i);
3344
3345 // display hex value of each of the next 8 bytes
3346 for (j = 0; j < 8; j++)
3347 DbgPrint("%02x ", *(PUCHAR)((ULONG_PTR)FileRecord + i + j));
3348 DbgPrint("\n");
3349 }
3350
3351 NtfsDumpFileAttributes(Vcb, FileRecord);
3352}
VOID NtfsDumpFileAttributes(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
Definition: attrib.c:1790

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

◆ NtfsFCBInitializeCache()

NTSTATUS NtfsFCBInitializeCache ( PNTFS_VCB  Vcb,
PNTFS_FCB  Fcb 
)

Definition at line 265 of file fcb.c.

267{
270 PNTFS_CCB newCCB;
271
272 FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice);
273
275 if (newCCB == NULL)
276 {
278 }
279
280 RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
281
282 newCCB->Identifier.Type = NTFS_TYPE_CCB;
283 newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
284
285 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
286 FileObject->FsContext = Fcb;
287 FileObject->FsContext2 = newCCB;
288 newCCB->PtrFileObject = FileObject;
290 Fcb->Vcb = Vcb;
291
294 {
297 FALSE,
299 Fcb);
300 }
302 {
303 FileObject->FsContext2 = NULL;
304 ExFreePoolWithTag(newCCB, TAG_CCB);
307 return _SEH2_GetExceptionCode();
308 }
309 _SEH2_END;
310
313
314 return Status;
315}
PFILE_OBJECT NTAPI IoCreateStreamFileObject(IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject)
Definition: file.c:3187
PFILE_OBJECT FileObject
Definition: ntfs.h:520
#define ObDereferenceObject
Definition: obfuncs.h:203

Referenced by NtfsMakeFCBFromDirEntry(), and NtfsMakeRootFCB().

◆ NtfsFCBIsCompressed()

BOOLEAN NtfsFCBIsCompressed ( PNTFS_FCB  Fcb)

Definition at line 146 of file fcb.c.

147{
149}
#define NTFS_FILE_TYPE_COMPRESSED
Definition: ntfs.h:229
FILENAME_ATTRIBUTE Entry
Definition: ntfs.h:542

Referenced by NtfsQueryDirectory(), NtfsReadFile(), and NtfsWriteFile().

◆ NtfsFCBIsDirectory()

◆ NtfsFCBIsEncrypted()

BOOLEAN NtfsFCBIsEncrypted ( PNTFS_FCB  Fcb)

Definition at line 152 of file fcb.c.

153{
155}
#define NTFS_FILE_TYPE_ENCRYPTED
Definition: ntfs.h:231

Referenced by NtfsReadFile().

◆ NtfsFCBIsReparsePoint()

BOOLEAN NtfsFCBIsReparsePoint ( PNTFS_FCB  Fcb)

Definition at line 139 of file fcb.c.

140{
142}
#define NTFS_FILE_TYPE_REPARSE
Definition: ntfs.h:228

Referenced by NtfsCreateFile().

◆ NtfsFCBIsRoot()

BOOLEAN NtfsFCBIsRoot ( PNTFS_FCB  Fcb)

Definition at line 158 of file fcb.c.

159{
160 return (wcscmp(Fcb->PathName, L"\\") == 0);
161}
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)

Referenced by NtfsMakeAbsoluteFilename(), and NtfsMakeFCBFromDirEntry().

◆ NtfsFileFlagsToAttributes()

VOID NtfsFileFlagsToAttributes ( ULONG  NtfsAttributes,
PULONG  FileAttributes 
)

Definition at line 105 of file misc.c.

107{
108 *FileAttributes = NtfsAttributes;
109 if ((NtfsAttributes & NTFS_FILE_TYPE_DIRECTORY) == NTFS_FILE_TYPE_DIRECTORY)
110 {
111 *FileAttributes = NtfsAttributes & ~NTFS_FILE_TYPE_DIRECTORY;
113 }
114
115 if (NtfsAttributes == 0)
117}
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE _In_ ACCESS_MASK _In_ POBJECT_ATTRIBUTES _Out_ PIO_STATUS_BLOCK _In_opt_ PLARGE_INTEGER _In_ ULONG FileAttributes
Definition: fltkernel.h:1236
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705

Referenced by NtfsGetBasicInformation(), NtfsGetBothDirectoryInformation(), NtfsGetDirectoryInformation(), NtfsGetFullDirectoryInformation(), and NtfsGetNetworkOpenInformation().

◆ NtfsFileSystemControl()

NTSTATUS NtfsFileSystemControl ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 963 of file fsctl.c.

964{
966 PIRP Irp;
968
969 DPRINT("NtfsFileSystemControl() called\n");
970
971 DeviceObject = IrpContext->DeviceObject;
972 Irp = IrpContext->Irp;
974
975 switch (IrpContext->MinorFunction)
976 {
978 DPRINT1("NTFS: IRP_MN_USER_FS_REQUEST\n");
980 break;
981
984 break;
985
987 DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n");
989 break;
990
992 DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n");
994 break;
995
996 default:
997 DPRINT1("NTFS FSC: MinorFunction %d\n", IrpContext->MinorFunction);
999 break;
1000 }
1001
1002 return Status;
1003}
static NTSTATUS NtfsVerifyVolume(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: fsctl.c:582
static NTSTATUS NtfsMountVolume(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: fsctl.c:416
static NTSTATUS NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: fsctl.c:900
#define IRP_MN_VERIFY_VOLUME
Definition: iotypes.h:4405
#define IRP_MN_USER_FS_REQUEST
Definition: iotypes.h:4403
#define IRP_MN_KERNEL_CALL
Definition: iotypes.h:4408
#define IRP_MN_MOUNT_VOLUME
Definition: iotypes.h:4404

Referenced by NtfsDispatch().

◆ NtfsFindFileAt()

NTSTATUS NtfsFindFileAt ( PDEVICE_EXTENSION  Vcb,
PUNICODE_STRING  SearchPattern,
PULONG  FirstEntry,
PFILE_RECORD_HEADER FileRecord,
PULONGLONG  MFTIndex,
ULONGLONG  CurrentMFTIndex,
BOOLEAN  CaseSensitive 
)

Definition at line 3355 of file mft.c.

3362{
3364
3365 DPRINT("NtfsFindFileAt(%p, %wZ, %lu, %p, %p, %I64x, %s)\n",
3366 Vcb,
3367 SearchPattern,
3368 *FirstEntry,
3369 FileRecord,
3370 MFTIndex,
3371 CurrentMFTIndex,
3372 (CaseSensitive ? "TRUE" : "FALSE"));
3373
3374 Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, SearchPattern, FirstEntry, TRUE, CaseSensitive, &CurrentMFTIndex);
3375 if (!NT_SUCCESS(Status))
3376 {
3377 DPRINT("NtfsFindFileAt: NtfsFindMftRecord() failed with status 0x%08lx\n", Status);
3378 return Status;
3379 }
3380
3381 *FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
3382 if (*FileRecord == NULL)
3383 {
3384 DPRINT("NtfsFindFileAt: Can't allocate MFT record\n");
3386 }
3387
3388 Status = ReadFileRecord(Vcb, CurrentMFTIndex, *FileRecord);
3389 if (!NT_SUCCESS(Status))
3390 {
3391 DPRINT("NtfsFindFileAt: Can't read MFT record\n");
3392 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, *FileRecord);
3393 return Status;
3394 }
3395
3396 *MFTIndex = CurrentMFTIndex;
3397
3398 return STATUS_SUCCESS;
3399}
NTSTATUS NtfsFindMftRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MFTIndex, PUNICODE_STRING FileName, PULONG FirstEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
Definition: mft.c:3146

Referenced by NtfsQueryDirectory().

◆ NtfsFindMftRecord()

NTSTATUS NtfsFindMftRecord ( PDEVICE_EXTENSION  Vcb,
ULONGLONG  MFTIndex,
PUNICODE_STRING  FileName,
PULONG  FirstEntry,
BOOLEAN  DirSearch,
BOOLEAN  CaseSensitive,
ULONGLONG OutMFTIndex 
)

Definition at line 3146 of file mft.c.

3153{
3154 PFILE_RECORD_HEADER MftRecord;
3155 PNTFS_ATTR_CONTEXT IndexRootCtx;
3156 PINDEX_ROOT_ATTRIBUTE IndexRoot;
3157 PCHAR IndexRecord;
3158 PINDEX_ENTRY_ATTRIBUTE IndexEntry, IndexEntryEnd;
3160 ULONG CurrentEntry = 0;
3161
3162 DPRINT("NtfsFindMftRecord(%p, %I64d, %wZ, %lu, %s, %s, %p)\n",
3163 Vcb,
3164 MFTIndex,
3165 FileName,
3166 *FirstEntry,
3167 DirSearch ? "TRUE" : "FALSE",
3168 CaseSensitive ? "TRUE" : "FALSE",
3169 OutMFTIndex);
3170
3171 MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
3172 if (MftRecord == NULL)
3173 {
3175 }
3176
3177 Status = ReadFileRecord(Vcb, MFTIndex, MftRecord);
3178 if (!NT_SUCCESS(Status))
3179 {
3180 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3181 return Status;
3182 }
3183
3184 ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
3185 Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
3186 if (!NT_SUCCESS(Status))
3187 {
3188 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3189 return Status;
3190 }
3191
3192 IndexRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerIndexRecord, TAG_NTFS);
3193 if (IndexRecord == NULL)
3194 {
3195 ReleaseAttributeContext(IndexRootCtx);
3196 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3198 }
3199
3200 ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, Vcb->NtfsInfo.BytesPerIndexRecord);
3201 IndexRoot = (PINDEX_ROOT_ATTRIBUTE)IndexRecord;
3202 IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)&IndexRoot->Header + IndexRoot->Header.FirstEntryOffset);
3203 /* Index root is always resident. */
3204 IndexEntryEnd = (PINDEX_ENTRY_ATTRIBUTE)(IndexRecord + IndexRoot->Header.TotalSizeOfEntries);
3205 ReleaseAttributeContext(IndexRootCtx);
3206
3207 DPRINT("IndexRecordSize: %x IndexBlockSize: %x\n", Vcb->NtfsInfo.BytesPerIndexRecord, IndexRoot->SizeOfEntry);
3208
3210 MftRecord,
3211 (PINDEX_ROOT_ATTRIBUTE)IndexRecord,
3212 IndexRoot->SizeOfEntry,
3213 IndexEntry,
3214 IndexEntryEnd,
3215 FileName,
3216 FirstEntry,
3217 &CurrentEntry,
3218 DirSearch,
3219 CaseSensitive,
3220 OutMFTIndex);
3221
3222 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
3223 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3224
3225 return Status;
3226}
struct INDEX_ROOT_ATTRIBUTE * PINDEX_ROOT_ATTRIBUTE
NTSTATUS BrowseIndexEntries(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER MftRecord, PINDEX_ROOT_ATTRIBUTE IndexRecord, ULONG IndexBlockSize, PINDEX_ENTRY_ATTRIBUTE FirstEntry, PINDEX_ENTRY_ATTRIBUTE LastEntry, PUNICODE_STRING FileName, PULONG StartEntry, PULONG CurrentEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
Definition: mft.c:2984

Referenced by NtfsFindFileAt(), and NtfsLookupFileAt().

◆ NtfsFsdDispatch()

NTSTATUS NTAPI NtfsFsdDispatch ( PDEVICE_OBJECT  DeviceObject,
PIRP  Irp 
)

Definition at line 185 of file dispatch.c.

187{
188 PNTFS_IRP_CONTEXT IrpContext = NULL;
190
191 TRACE_(NTFS, "NtfsFsdDispatch()\n");
192
194 if (IrpContext == NULL)
195 {
197 Irp->IoStatus.Status = Status;
199 }
200 else
201 {
202 Status = NtfsDispatch(IrpContext);
203 }
204
205 return Status;
206}
static NTSTATUS NtfsDispatch(PNTFS_IRP_CONTEXT IrpContext)
Definition: dispatch.c:59
PNTFS_IRP_CONTEXT NtfsAllocateIrpContext(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: misc.c:66
#define IoCompleteRequest
Definition: irp.c:1240

◆ NtfsGetFCBForFile()

NTSTATUS NtfsGetFCBForFile ( PNTFS_VCB  Vcb,
PNTFS_FCB pParentFCB,
PNTFS_FCB pFCB,
PCWSTR  pFileName,
BOOLEAN  CaseSensitive 
)

Definition at line 603 of file fcb.c.

608{
610 WCHAR pathName [MAX_PATH];
611 WCHAR elementName [MAX_PATH];
612 PCWSTR currentElement;
614 PNTFS_FCB parentFCB;
615
616 DPRINT("NtfsGetFCBForFile(%p, %p, %p, '%S', %s)\n",
617 Vcb,
618 pParentFCB,
619 pFCB,
620 pFileName,
621 CaseSensitive ? "TRUE" : "FALSE");
622
623 /* Dummy code */
624// FCB = NtfsOpenRootFCB(Vcb);
625// *pFCB = FCB;
626// *pParentFCB = NULL;
627
628#if 1
629 /* Trivial case, open of the root directory on volume */
630 if (pFileName[0] == L'\0' || wcscmp(pFileName, L"\\") == 0)
631 {
632 DPRINT("returning root FCB\n");
633
635 *pFCB = FCB;
636 *pParentFCB = NULL;
637
639 }
640 else
641 {
642 currentElement = pFileName + 1;
643 wcscpy (pathName, L"\\");
645 }
646
647 parentFCB = NULL;
648
649 /* Parse filename and check each path element for existence and access */
650 while (NtfsGetNextPathElement(currentElement) != 0)
651 {
652 /* Skip blank directory levels */
653 if ((NtfsGetNextPathElement(currentElement) - currentElement) == 0)
654 {
655 currentElement++;
656 continue;
657 }
658
659 DPRINT("Parsing, currentElement:%S\n", currentElement);
660 DPRINT(" parentFCB:%p FCB:%p\n", parentFCB, FCB);
661
662 /* Descend to next directory level */
663 if (parentFCB)
664 {
665 NtfsReleaseFCB(Vcb, parentFCB);
666 parentFCB = NULL;
667 }
668
669 /* fail if element in FCB is not a directory */
671 {
672 DPRINT("Element in requested path is not a directory\n");
673
675 FCB = 0;
676 *pParentFCB = NULL;
677 *pFCB = NULL;
678
680 }
681
682 parentFCB = FCB;
683
684 /* Extract next directory level into dirName */
685 NtfsWSubString(pathName,
686 pFileName,
687 NtfsGetNextPathElement(currentElement) - pFileName);
688 DPRINT(" pathName:%S\n", pathName);
689
690 FCB = NtfsGrabFCBFromTable(Vcb, pathName);
691 if (FCB == NULL)
692 {
693 NtfsWSubString(elementName,
694 currentElement,
695 NtfsGetNextPathElement(currentElement) - currentElement);
696 DPRINT(" elementName:%S\n", elementName);
697
698 Status = NtfsDirFindFile(Vcb, parentFCB, elementName, CaseSensitive, &FCB);
700 {
701 *pParentFCB = parentFCB;
702 *pFCB = NULL;
703 currentElement = NtfsGetNextPathElement(currentElement);
704 if (*currentElement == L'\0' || NtfsGetNextPathElement(currentElement + 1) == 0)
705 {
707 }
708 else
709 {
711 }
712 }
713 else if (!NT_SUCCESS(Status))
714 {
715 NtfsReleaseFCB(Vcb, parentFCB);
716 *pParentFCB = NULL;
717 *pFCB = NULL;
718
719 return Status;
720 }
721 }
722
723 currentElement = NtfsGetNextPathElement(currentElement);
724 }
725
726 *pParentFCB = parentFCB;
727 *pFCB = FCB;
728#endif
729
730 return STATUS_SUCCESS;
731}
struct _FCB FCB
#define MAX_PATH
Definition: compat.h:34
static VOID NtfsWSubString(PWCHAR pTarget, PCWSTR pSource, size_t pLength)
Definition: fcb.c:57
BOOLEAN NtfsFCBIsDirectory(PNTFS_FCB Fcb)
Definition: fcb.c:132
PNTFS_FCB NtfsGrabFCBFromTable(PNTFS_VCB Vcb, PCWSTR FileName)
Definition: fcb.c:222
static NTSTATUS NtfsDirFindFile(PNTFS_VCB Vcb, PNTFS_FCB DirectoryFcb, PWSTR FileToFind, BOOLEAN CaseSensitive, PNTFS_FCB *FoundFCB)
Definition: fcb.c:515
PNTFS_FCB NtfsOpenRootFCB(PNTFS_VCB Vcb)
Definition: fcb.c:374
static PCWSTR NtfsGetNextPathElement(PCWSTR FileName)
Definition: fcb.c:39
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151

Referenced by NtfsOpenFile().

◆ NtfsGetFileSize()

ULONGLONG NtfsGetFileSize ( PDEVICE_EXTENSION  DeviceExt,
PFILE_RECORD_HEADER  FileRecord,
PCWSTR  Stream,
ULONG  StreamLength,
PULONGLONG  AllocatedSize 
)

Definition at line 38 of file dirctl.c.

43{
47 PNTFS_ATTR_CONTEXT DataContext;
48
49 Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Stream, StreamLength, &DataContext, NULL);
50 if (NT_SUCCESS(Status))
51 {
52 Size = AttributeDataLength(DataContext->pRecord);
53 Allocated = AttributeAllocatedLength(DataContext->pRecord);
54 ReleaseAttributeContext(DataContext);
55 }
56
57 if (AllocatedSize != NULL) *AllocatedSize = Allocated;
58
59 return Size;
60}
IN PFCB IN VBO OUT PLBO OUT PULONG OUT PBOOLEAN Allocated
Definition: fatprocs.h:310
ULONGLONG AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:249
#define ULL(a, b)
Definition: format_msg.c:27
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533

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

◆ NtfsGetFreeClusters()

ULONGLONG NtfsGetFreeClusters ( PDEVICE_EXTENSION  DeviceExt)

Definition at line 37 of file volinfo.c.

38{
40 PFILE_RECORD_HEADER BitmapRecord;
41 PNTFS_ATTR_CONTEXT DataContext;
42 ULONGLONG BitmapDataSize;
45 ULONG Read = 0;
47
48 DPRINT("NtfsGetFreeClusters(%p)\n", DeviceExt);
49
50 BitmapRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
51 if (BitmapRecord == NULL)
52 {
53 return 0;
54 }
55
56 Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord);
57 if (!NT_SUCCESS(Status))
58 {
59 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
60 return 0;
61 }
62
63 Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL);
64 if (!NT_SUCCESS(Status))
65 {
66 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
67 return 0;
68 }
69
70 BitmapDataSize = AttributeDataLength(DataContext->pRecord);
71 ASSERT((BitmapDataSize * 8) >= DeviceExt->NtfsInfo.ClusterCount);
72 BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS);
73 if (BitmapData == NULL)
74 {
75 ReleaseAttributeContext(DataContext);
76 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
77 return 0;
78 }
79
80 /* FIXME: Totally underoptimized! */
81 for (; Read < BitmapDataSize; Read += DeviceExt->NtfsInfo.BytesPerSector)
82 {
83 ReadAttribute(DeviceExt, DataContext, Read, (PCHAR)((ULONG_PTR)BitmapData + Read), DeviceExt->NtfsInfo.BytesPerSector);
84 }
85 ReleaseAttributeContext(DataContext);
86
87 DPRINT1("Total clusters: %I64x\n", DeviceExt->NtfsInfo.ClusterCount);
88 DPRINT1("Total clusters in bitmap: %I64x\n", BitmapDataSize * 8);
89 DPRINT1("Diff in size: %I64d B\n", ((BitmapDataSize * 8) - DeviceExt->NtfsInfo.ClusterCount) * DeviceExt->NtfsInfo.SectorsPerCluster * DeviceExt->NtfsInfo.BytesPerSector);
90
91 RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.ClusterCount);
93
95 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
96
97 return FreeClusters;
98}
_In_ BOOLEAN Read
Definition: strmini.h:479

Referenced by GetNfsVolumeData(), and NtfsGetFsSizeInformation().

◆ NtfsGetUserBuffer()

PVOID NtfsGetUserBuffer ( PIRP  Irp,
BOOLEAN  Paging 
)

Definition at line 120 of file misc.c.

122{
123 if (Irp->MdlAddress != NULL)
124 {
126 }
127 else
128 {
129 return Irp->UserBuffer;
130 }
131}
@ NormalPagePriority
Definition: imports.h:56
@ HighPagePriority
Definition: imports.h:57
#define MmGetSystemAddressForMdlSafe(_Mdl, _Priority)

Referenced by GetVolumeBitmap(), NtfsQueryDirectory(), NtfsRead(), and NtfsWrite().

◆ NtfsGrabFCB()

VOID NtfsGrabFCB ( PNTFS_VCB  Vcb,
PNTFS_FCB  Fcb 
)

Definition at line 165 of file fcb.c.

167{
168 KIRQL oldIrql;
169
170 DPRINT("grabbing FCB at %p: %S, refCount:%d\n",
171 Fcb,
172 Fcb->PathName,
173 Fcb->RefCount);
174
175 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
176 Fcb->RefCount++;
177 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
178}
LONG RefCount
Definition: ntfs.h:535

Referenced by NtfsMakeRootFCB().

◆ NtfsGrabFCBFromTable()

PNTFS_FCB NtfsGrabFCBFromTable ( PNTFS_VCB  Vcb,
PCWSTR  FileName 
)

Definition at line 222 of file fcb.c.

224{
225 KIRQL oldIrql;
227 PLIST_ENTRY current_entry;
228
229 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
230
231 if (FileName == NULL || *FileName == 0)
232 {
233 DPRINT("Return FCB for stream file object\n");
234 Fcb = Vcb->StreamFileObject->FsContext;
235 Fcb->RefCount++;
236 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
237 return Fcb;
238 }
239
240 current_entry = Vcb->FcbListHead.Flink;
241 while (current_entry != &Vcb->FcbListHead)
242 {
243 Fcb = CONTAINING_RECORD(current_entry, NTFS_FCB, FcbListEntry);
244
245 DPRINT("Comparing '%S' and '%S'\n", FileName, Fcb->PathName);
246 if (_wcsicmp(FileName, Fcb->PathName) == 0)
247 {
248 Fcb->RefCount++;
249 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
250 return Fcb;
251 }
252
253 //FIXME: need to compare against short name in FCB here
254
255 current_entry = current_entry->Flink;
256 }
257
258 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
259
260 return NULL;
261}
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260

Referenced by NtfsGetFCBForFile(), NtfsOpenFile(), NtfsOpenFileById(), and NtfsOpenRootFCB().

◆ NtfsInitializeFunctionPointers()

VOID NTAPI NtfsInitializeFunctionPointers ( PDRIVER_OBJECT  DriverObject)

Definition at line 170 of file ntfs.c.

171{
173 DriverObject->MajorFunction[IRP_MJ_CLOSE] = NtfsFsdDispatch;
175 DriverObject->MajorFunction[IRP_MJ_READ] = NtfsFsdDispatch;
176 DriverObject->MajorFunction[IRP_MJ_WRITE] = NtfsFsdDispatch;
184
185 return;
186}
DRIVER_DISPATCH NtfsFsdDispatch
Definition: ntfs.h:892
#define IRP_MJ_DIRECTORY_CONTROL
Definition: rdpdr.c:51
#define IRP_MJ_READ
Definition: rdpdr.c:46
#define IRP_MJ_QUERY_VOLUME_INFORMATION
Definition: rdpdr.c:50
#define IRP_MJ_WRITE
Definition: rdpdr.c:47
#define IRP_MJ_SET_INFORMATION
Definition: rdpdr.c:49
#define IRP_MJ_CREATE
Definition: rdpdr.c:44
#define IRP_MJ_QUERY_INFORMATION
Definition: rdpdr.c:48
_Must_inspect_result_ _In_ PDRIVER_OBJECT DriverObject
Definition: wdfdriver.h:213
#define IRP_MJ_SET_VOLUME_INFORMATION

Referenced by DriverEntry().

◆ NtfsInsertKey()

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 at line 1691 of file btree.c.

1700{
1701 PB_TREE_KEY NewKey, CurrentKey, PreviousKey;
1703 ULONG NodeSize;
1704 ULONG AllocatedNodeSize;
1705 ULONG MaxNodeSizeWithoutHeader;
1706 ULONG i;
1707
1708 *MedianKey = NULL;
1709 *NewRightHandSibling = NULL;
1710
1711 DPRINT("NtfsInsertKey(%p, 0x%I64x, %p, %p, %s, %lu, %lu, %p, %p)\n",
1712 Tree,
1713 FileReference,
1714 FileNameAttribute,
1715 Node,
1716 CaseSensitive ? "TRUE" : "FALSE",
1717 MaxIndexRootSize,
1718 IndexRecordSize,
1719 MedianKey,
1720 NewRightHandSibling);
1721
1722 // Create the key for the filename attribute
1723 NewKey = CreateBTreeKeyFromFilename(FileReference, FileNameAttribute);
1724 if (!NewKey)
1726
1727 // Find where to insert the key
1728 CurrentKey = Node->FirstKey;
1729 PreviousKey = NULL;
1730 for (i = 0; i < Node->KeyCount; i++)
1731 {
1732 // Should the New Key go before the current key?
1733 LONG Comparison = CompareTreeKeys(NewKey, CurrentKey, CaseSensitive);
1734
1735 if (Comparison == 0)
1736 {
1737 DPRINT1("\t\tComparison == 0: %.*S\n", NewKey->IndexEntry->FileName.NameLength, NewKey->IndexEntry->FileName.Name);
1738 DPRINT1("\t\tComparison == 0: %.*S\n", CurrentKey->IndexEntry->FileName.NameLength, CurrentKey->IndexEntry->FileName.Name);
1739 }
1740 ASSERT(Comparison != 0);
1741
1742 // Is NewKey < CurrentKey?
1743 if (Comparison < 0)
1744 {
1745 // Does CurrentKey have a sub-node?
1746 if (CurrentKey->LesserChild)
1747 {
1748 PB_TREE_KEY NewLeftKey;
1749 PB_TREE_FILENAME_NODE NewChild;
1750
1751 // Insert the key into the child node
1753 FileReference,
1754 FileNameAttribute,
1755 CurrentKey->LesserChild,
1756 CaseSensitive,
1757 MaxIndexRootSize,
1758 IndexRecordSize,
1759 &NewLeftKey,
1760 &NewChild);
1761 if (!NT_SUCCESS(Status))
1762 {
1763 DPRINT1("ERROR: Failed to insert key.\n");
1764 ExFreePoolWithTag(NewKey, TAG_NTFS);
1765 return Status;
1766 }
1767
1768 // Did the child node get split?
1769 if (NewLeftKey)
1770 {
1771 ASSERT(NewChild != NULL);
1772
1773 // Insert the new left key to the left of the current key
1774 NewLeftKey->NextKey = CurrentKey;
1775
1776 // Is CurrentKey the first key?
1777 if (!PreviousKey)
1778 Node->FirstKey = NewLeftKey;
1779 else
1780 PreviousKey->NextKey = NewLeftKey;
1781
1782 // CurrentKey->LesserChild will be the right-hand sibling
1783 CurrentKey->LesserChild = NewChild;
1784
1785 Node->KeyCount++;
1786 Node->DiskNeedsUpdating = TRUE;
1787
1788#ifndef NDEBUG
1789 DumpBTree(Tree);
1790#endif
1791 }
1792 }
1793 else
1794 {
1795 // Insert New Key before Current Key
1796 NewKey->NextKey = CurrentKey;
1797
1798 // Increase KeyCount and mark node as dirty
1799 Node->KeyCount++;
1800 Node->DiskNeedsUpdating = TRUE;
1801
1802 // was CurrentKey the first key?
1803 if (CurrentKey == Node->FirstKey)
1804 Node->FirstKey = NewKey;
1805 else
1806 PreviousKey->NextKey = NewKey;
1807 }
1808 break;
1809 }
1810
1811 PreviousKey = CurrentKey;
1812 CurrentKey = CurrentKey->NextKey;
1813 }
1814
1815 // Determine how much space the index entries will need
1816 NodeSize = GetSizeOfIndexEntries(Node);
1817
1818 // Is Node not the root node?
1819 if (Node != Tree->RootNode)
1820 {
1821 // Calculate maximum size of index entries without any headers
1822 AllocatedNodeSize = IndexRecordSize - FIELD_OFFSET(INDEX_BUFFER, Header);
1823
1824 // TODO: Replace magic with math
1825 MaxNodeSizeWithoutHeader = AllocatedNodeSize - 0x28;
1826
1827 // Has the node grown larger than its allocated size?
1828 if (NodeSize > MaxNodeSizeWithoutHeader)
1829 {
1831
1832 Status = SplitBTreeNode(Tree, Node, MedianKey, NewRightHandSibling, CaseSensitive);
1833 if (!NT_SUCCESS(Status))
1834 {
1835 DPRINT1("ERROR: Failed to split B-Tree node!\n");
1836 return Status;
1837 }
1838
1839 return Status;
1840 }
1841 }
1842
1843 // NewEntry and NewKey will be destroyed later by DestroyBTree()
1844
1845 return Status;
1846}
LONG CompareTreeKeys(PB_TREE_KEY Key1, PB_TREE_KEY Key2, BOOLEAN CaseSensitive)
Definition: btree.c:417
NTSTATUS SplitBTreeNode(PB_TREE Tree, PB_TREE_FILENAME_NODE Node, PB_TREE_KEY *MedianKey, PB_TREE_FILENAME_NODE *NewRightHandSibling, BOOLEAN CaseSensitive)
Definition: btree.c:1883
PB_TREE_KEY CreateBTreeKeyFromFilename(ULONGLONG FileReference, PFILENAME_ATTRIBUTE FileNameAttribute)
Definition: btree.c:1461

Referenced by NtfsAddFilenameToDirectory(), and NtfsInsertKey().

◆ NtfsIsIrpTopLevel()

BOOLEAN NtfsIsIrpTopLevel ( PIRP  Irp)

Definition at line 43 of file misc.c.

44{
45 BOOLEAN ReturnCode = FALSE;
46
47 TRACE_(NTFS, "NtfsIsIrpTopLevel()\n");
48
49 if (IoGetTopLevelIrp() == NULL)
50 {
52 ReturnCode = TRUE;
53 }
54
55 return ReturnCode;
56}
VOID NTAPI IoSetTopLevelIrp(IN PIRP Irp)
Definition: irp.c:2000

Referenced by NtfsDispatch().

◆ NtfsLockUserBuffer()

NTSTATUS NtfsLockUserBuffer ( IN PIRP  Irp,
IN ULONG  Length,
IN LOCK_OPERATION  Operation 
)

Definition at line 158 of file misc.c.

161{
162 ASSERT(Irp);
163
164 if (Irp->MdlAddress)
165 {
166 return STATUS_SUCCESS;
167 }
168
169 IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
170
171 if (!Irp->MdlAddress)
172 {
174 }
175
177 {
178 MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
179 }
181 {
182 IoFreeMdl(Irp->MdlAddress);
183 Irp->MdlAddress = NULL;
185 }
186 _SEH2_END;
187
188 return STATUS_SUCCESS;
189}
FP_OP Operation
Definition: fpcontrol.c:150
#define IoFreeMdl
Definition: fxmdl.h:89
#define IoAllocateMdl
Definition: fxmdl.h:88
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:931

Referenced by NtfsWrite().

◆ NtfsLookupFile()

NTSTATUS NtfsLookupFile ( PDEVICE_EXTENSION  Vcb,
PUNICODE_STRING  PathName,
BOOLEAN  CaseSensitive,
PFILE_RECORD_HEADER FileRecord,
PULONGLONG  MFTIndex 
)

Definition at line 3287 of file mft.c.

3292{
3293 return NtfsLookupFileAt(Vcb, PathName, CaseSensitive, FileRecord, MFTIndex, NTFS_FILE_ROOT);
3294}
NTSTATUS NtfsLookupFileAt(PDEVICE_EXTENSION Vcb, PUNICODE_STRING PathName, BOOLEAN CaseSensitive, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex, ULONGLONG CurrentMFTIndex)
Definition: mft.c:3229

◆ NtfsLookupFileAt()

NTSTATUS NtfsLookupFileAt ( PDEVICE_EXTENSION  Vcb,
PUNICODE_STRING  PathName,
BOOLEAN  CaseSensitive,
PFILE_RECORD_HEADER FileRecord,
PULONGLONG  MFTIndex,
ULONGLONG  CurrentMFTIndex 
)

Definition at line 3229 of file mft.c.

3235{
3236 UNICODE_STRING Current, Remaining;
3238 ULONG FirstEntry = 0;
3239
3240 DPRINT("NtfsLookupFileAt(%p, %wZ, %s, %p, %p, %I64x)\n",
3241 Vcb,
3242 PathName,
3243 CaseSensitive ? "TRUE" : "FALSE",
3244 FileRecord,
3245 MFTIndex,
3246 CurrentMFTIndex);
3247
3248 FsRtlDissectName(*PathName, &Current, &Remaining);
3249
3250 while (Current.Length != 0)
3251 {
3252 DPRINT("Current: %wZ\n", &Current);
3253
3254 Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, &Current, &FirstEntry, FALSE, CaseSensitive, &CurrentMFTIndex);
3255 if (!NT_SUCCESS(Status))
3256 {
3257 return Status;
3258 }
3259
3260 if (Remaining.Length == 0)
3261 break;
3262
3263 FsRtlDissectName(Current, &Current, &Remaining);
3264 }
3265
3266 *FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
3267 if (*FileRecord == NULL)
3268 {
3269 DPRINT("NtfsLookupFileAt: Can't allocate MFT record\n");
3271 }
3272
3273 Status = ReadFileRecord(Vcb, CurrentMFTIndex, *FileRecord);
3274 if (!NT_SUCCESS(Status))
3275 {
3276 DPRINT("NtfsLookupFileAt: Can't read MFT record\n");
3277 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, *FileRecord);
3278 return Status;
3279 }
3280
3281 *MFTIndex = CurrentMFTIndex;
3282
3283 return STATUS_SUCCESS;
3284}

Referenced by NtfsDirFindFile(), and NtfsLookupFile().

◆ NtfsMakeFCBFromDirEntry()

NTSTATUS NtfsMakeFCBFromDirEntry ( PNTFS_VCB  Vcb,
PNTFS_FCB  DirectoryFCB,
PUNICODE_STRING  Name,
PCWSTR  Stream,
PFILE_RECORD_HEADER  Record,
ULONGLONG  MFTIndex,
PNTFS_FCB fileFCB 
)

Definition at line 389 of file fcb.c.

396{
397 WCHAR pathName[MAX_PATH];
399 PSTANDARD_INFORMATION StdInfo;
400 PNTFS_FCB rcFCB;
401 ULONGLONG Size, AllocatedSize;
402
403 DPRINT("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p, %p)\n", Vcb, DirectoryFCB, Name, Stream, Record, fileFCB);
404
406 if (!FileName)
407 {
408 return STATUS_OBJECT_NAME_NOT_FOUND; // Not sure that's the best here
409 }
410
411 if (DirectoryFCB && Name)
412 {
413 if (Name->Buffer[0] != 0 && wcslen(DirectoryFCB->PathName) +
414 sizeof(WCHAR) + Name->Length / sizeof(WCHAR) > MAX_PATH)
415 {
417 }
418
419 wcscpy(pathName, DirectoryFCB->PathName);
420 if (!NtfsFCBIsRoot(DirectoryFCB))
421 {
422 wcscat(pathName, L"\\");
423 }
424 wcscat(pathName, Name->Buffer);
425 }
426 else
427 {
428 RtlCopyMemory(pathName, FileName->Name, FileName->NameLength * sizeof (WCHAR));
429 pathName[FileName->NameLength] = UNICODE_NULL;
430 }
431
432 Size = NtfsGetFileSize(Vcb, Record, (Stream ? Stream : L""), (Stream ? wcslen(Stream) : 0), &AllocatedSize);
433
434 rcFCB = NtfsCreateFCB(pathName, Stream, Vcb);
435 if (!rcFCB)
436 {
438 }
439
440 memcpy(&rcFCB->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
441 rcFCB->Entry.NameType = FileName->NameType;
442 rcFCB->RFCB.FileSize.QuadPart = Size;
444 rcFCB->RFCB.AllocationSize.QuadPart = AllocatedSize;
445
447 if (StdInfo != NULL)
448 {
449 rcFCB->Entry.FileAttributes |= StdInfo->FileAttribute;
450 }
451
453 rcFCB->RefCount = 1;
454 rcFCB->MFTIndex = MFTIndex;
455 rcFCB->LinkCount = Record->LinkCount;
456 NtfsAddFCBToTable(Vcb, rcFCB);
457 *fileFCB = rcFCB;
458
459 return STATUS_SUCCESS;
460}
PSTANDARD_INFORMATION GetStandardInformationFromRecord(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
Definition: attrib.c:1940
PFILENAME_ATTRIBUTE GetBestFileNameFromRecord(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
Definition: attrib.c:1985
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
ULONGLONG NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt, PFILE_RECORD_HEADER FileRecord, PCWSTR Stream, ULONG StreamLength, PULONGLONG AllocatedSize)
Definition: dirctl.c:38
BOOLEAN NtfsFCBIsRoot(PNTFS_FCB Fcb)
Definition: fcb.c:158
NTSTATUS NtfsFCBInitializeCache(PNTFS_VCB Vcb, PNTFS_FCB Fcb)
Definition: fcb.c:265
PNTFS_FCB NtfsCreateFCB(PCWSTR FileName, PCWSTR Stream, PNTFS_VCB Vcb)
Definition: fcb.c:67
VOID NtfsAddFCBToTable(PNTFS_VCB Vcb, PNTFS_FCB Fcb)
Definition: fcb.c:209
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
ULONGLONG MFTIndex
Definition: ntfs.h:539
USHORT LinkCount
Definition: ntfs.h:540
LARGE_INTEGER ValidDataLength
Definition: env_spec_w32.h:757
TCHAR Name[MAX_PATH]
Definition: filecomp.c:349
#define STATUS_OBJECT_NAME_INVALID
Definition: udferr_usr.h:148
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList

Referenced by NtfsDirFindFile(), and NtfsOpenFileById().

◆ NtfsMakeRootFCB()

PNTFS_FCB NtfsMakeRootFCB ( PNTFS_VCB  Vcb)

Definition at line 319 of file fcb.c.

320{
322 PFILE_RECORD_HEADER MftRecord;
324
325 MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
326 if (MftRecord == NULL)
327 {
328 return NULL;
329 }
330
331 if (!NT_SUCCESS(ReadFileRecord(Vcb, NTFS_FILE_ROOT, MftRecord)))
332 {
333 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
334 return NULL;
335 }
336
338 if (!FileName)
339 {
340 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
341 return NULL;
342 }
343
344 Fcb = NtfsCreateFCB(L"\\", NULL, Vcb);
345 if (!Fcb)
346 {
347 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
348 return NULL;
349 }
350
352 Fcb->Entry.NameType = FileName->NameType;
353 Fcb->Entry.NameLength = 0;
355 Fcb->RefCount = 1;
356 Fcb->DirIndex = 0;
357 Fcb->RFCB.FileSize.QuadPart = FileName->DataSize;
359 Fcb->RFCB.AllocationSize.QuadPart = FileName->AllocatedSize;
361 Fcb->LinkCount = MftRecord->LinkCount;
362
366
367 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
368
369 return Fcb;
370}
VOID NtfsGrabFCB(PNTFS_VCB Vcb, PNTFS_FCB Fcb)
Definition: fcb.c:165
ULONG DirIndex
Definition: ntfs.h:533

Referenced by NtfsOpenRootFCB().

◆ NtfsMarkIrpContextForQueue()

FORCEINLINE NTSTATUS NtfsMarkIrpContextForQueue ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 569 of file ntfs.h.

570{
571 PULONG Flags = &IrpContext->Flags;
572
573 *Flags &= ~IRPCONTEXT_COMPLETE;
575
576 return STATUS_PENDING;
577}
#define IRPCONTEXT_QUEUE
Definition: ntfs.h:476
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170

Referenced by NtfsCleanup(), NtfsClose(), NtfsCreate(), NtfsDirectoryControl(), NtfsQueryInformation(), NtfsQueryVolumeInformation(), and NtfsSetInformation().

◆ NtfsOpenRootFCB()

PNTFS_FCB NtfsOpenRootFCB ( PNTFS_VCB  Vcb)

Definition at line 374 of file fcb.c.

375{
377
379 if (Fcb == NULL)
380 {
382 }
383
384 return Fcb;
385}
PNTFS_FCB NtfsMakeRootFCB(PNTFS_VCB Vcb)
Definition: fcb.c:319

Referenced by NtfsGetFCBForFile().

◆ NtfsQueryInformation()

NTSTATUS NtfsQueryInformation ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 420 of file finfo.c.

421{
426 PVOID SystemBuffer;
428 PIRP Irp;
431
432 DPRINT1("NtfsQueryInformation(%p)\n", IrpContext);
433
434 Irp = IrpContext->Irp;
435 Stack = IrpContext->Stack;
436 DeviceObject = IrpContext->DeviceObject;
437 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass;
438 FileObject = IrpContext->FileObject;
439 Fcb = FileObject->FsContext;
440
441 SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
442 BufferLength = Stack->Parameters.QueryFile.Length;
443
446 {
447 return NtfsMarkIrpContextForQueue(IrpContext);
448 }
449
450 switch (FileInformationClass)
451 {
455 SystemBuffer,
456 &BufferLength);
457 break;
458
461 SystemBuffer,
462 &BufferLength);
463 break;
464
467 Fcb,
469 SystemBuffer,
470 &BufferLength);
471 break;
472
475 Fcb,
477 SystemBuffer,
478 &BufferLength);
479 break;
480
483 SystemBuffer,
484 &BufferLength);
485 break;
486
489 DeviceObject->DeviceExtension,
490 SystemBuffer,
491 &BufferLength);
492 break;
493
496 DeviceObject->DeviceExtension,
497 SystemBuffer,
498 &BufferLength);
499 break;
500
503 DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass));
505 break;
506
507 default:
508 DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass));
510 }
511
513
514 if (NT_SUCCESS(Status))
515 Irp->IoStatus.Information =
516 Stack->Parameters.QueryFile.Length - BufferLength;
517 else
518 Irp->IoStatus.Information = 0;
519
520 return Status;
521}
#define ExAcquireResourceSharedLite(res, wait)
Definition: env_spec_w32.h:621
@ FilePositionInformation
Definition: from_kernel.h:75
@ FileAllInformation
Definition: from_kernel.h:79
@ FileInternalInformation
Definition: from_kernel.h:67
@ FileAlternateNameInformation
Definition: from_kernel.h:82
@ FileNameInformation
Definition: from_kernel.h:70
@ FileNetworkOpenInformation
Definition: from_kernel.h:95
@ FileStreamInformation
Definition: from_kernel.h:83
@ FileBasicInformation
Definition: from_kernel.h:65
enum _FILE_INFORMATION_CLASS FILE_INFORMATION_CLASS
Definition: directory.c:44
static OUT PIO_STATUS_BLOCK OUT PVOID IN ULONG IN FILE_INFORMATION_CLASS FileInformationClass
Definition: pipe.c:75
static NTSTATUS NtfsGetNameInformation(PFILE_OBJECT FileObject, PNTFS_FCB Fcb, PDEVICE_OBJECT DeviceObject, PFILE_NAME_INFORMATION NameInfo, PULONG BufferLength)
Definition: finfo.c:130
static NTSTATUS NtfsGetStreamInformation(PNTFS_FCB Fcb, PDEVICE_EXTENSION DeviceExt, PFILE_STREAM_INFORMATION StreamInfo, PULONG BufferLength)
Definition: finfo.c:226
static NTSTATUS NtfsGetPositionInformation(PFILE_OBJECT FileObject, PFILE_POSITION_INFORMATION PositionInfo, PULONG BufferLength)
Definition: finfo.c:75
const PCSTR GetInfoClassName(FILE_INFORMATION_CLASS infoClass)
Definition: finfo.c:296
static NTSTATUS NtfsGetStandardInformation(PNTFS_FCB Fcb, PDEVICE_OBJECT DeviceObject, PFILE_STANDARD_INFORMATION StandardInfo, PULONG BufferLength)
Definition: finfo.c:42
static NTSTATUS NtfsGetNetworkOpenInformation(PNTFS_FCB Fcb, PDEVICE_EXTENSION DeviceExt, PFILE_NETWORK_OPEN_INFORMATION NetworkInfo, PULONG BufferLength)
Definition: finfo.c:198
static NTSTATUS NtfsGetInternalInformation(PNTFS_FCB Fcb, PFILE_INTERNAL_INFORMATION InternalInfo, PULONG BufferLength)
Definition: finfo.c:177
static NTSTATUS NtfsGetBasicInformation(PFILE_OBJECT FileObject, PNTFS_FCB Fcb, PDEVICE_OBJECT DeviceObject, PFILE_BASIC_INFORMATION BasicInfo, PULONG BufferLength)
Definition: finfo.c:97
#define FileStandardInformation
Definition: propsheet.cpp:61
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3771

Referenced by NtfsDispatch().

◆ NtfsQueryVolumeInformation()

NTSTATUS NtfsQueryVolumeInformation ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 343 of file volinfo.c.

344{
345 PIRP Irp;
350 PVOID SystemBuffer;
352 PDEVICE_EXTENSION DeviceExt;
353
354 DPRINT("NtfsQueryVolumeInformation() called\n");
355
356 ASSERT(IrpContext);
357
358 Irp = IrpContext->Irp;
359 DeviceObject = IrpContext->DeviceObject;
360 DeviceExt = DeviceObject->DeviceExtension;
361 Stack = IrpContext->Stack;
362
363 if (!ExAcquireResourceSharedLite(&DeviceExt->DirResource,
365 {
366 return NtfsMarkIrpContextForQueue(IrpContext);
367 }
368
369 FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
370 BufferLength = Stack->Parameters.QueryVolume.Length;
371 SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
372 RtlZeroMemory(SystemBuffer, BufferLength);
373
374 DPRINT("FsInformationClass %d\n", FsInformationClass);
375 DPRINT("SystemBuffer %p\n", SystemBuffer);
376
377 switch (FsInformationClass)
378 {
381 SystemBuffer,
382 &BufferLength);
383 break;
384
387 SystemBuffer,
388 &BufferLength);
389 break;
390
393 SystemBuffer,
394 &BufferLength);
395 break;
396
399 SystemBuffer,
400 &BufferLength);
401 break;
402
403 default:
405 }
406
407 ExReleaseResourceLite(&DeviceExt->DirResource);
408
409 if (NT_SUCCESS(Status))
410 Irp->IoStatus.Information =
411 Stack->Parameters.QueryVolume.Length - BufferLength;
412 else
413 Irp->IoStatus.Information = 0;
414
415 return Status;
416}
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ ULONG _In_ FS_INFORMATION_CLASS FsInformationClass
Definition: fltkernel.h:1330
@ FileFsDeviceInformation
Definition: from_kernel.h:222
@ FileFsAttributeInformation
Definition: from_kernel.h:223
@ FileFsVolumeInformation
Definition: from_kernel.h:219
@ FileFsSizeInformation
Definition: from_kernel.h:221
enum _FSINFOCLASS FS_INFORMATION_CLASS
static NTSTATUS NtfsGetFsDeviceInformation(PDEVICE_OBJECT DeviceObject, PFILE_FS_DEVICE_INFORMATION FsDeviceInfo, PULONG BufferLength)
Definition: volinfo.c:318
static NTSTATUS NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject, PFILE_FS_VOLUME_INFORMATION FsVolumeInfo, PULONG BufferLength)
Definition: volinfo.c:207
static NTSTATUS NtfsGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt, PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo, PULONG BufferLength)
Definition: volinfo.c:253
static NTSTATUS NtfsGetFsSizeInformation(PDEVICE_OBJECT DeviceObject, PFILE_FS_SIZE_INFORMATION FsSizeInfo, PULONG BufferLength)
Definition: volinfo.c:288
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:423

Referenced by NtfsDispatch().

◆ NtfsRead()

NTSTATUS NtfsRead ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 216 of file rw.c.

217{
218 PDEVICE_EXTENSION DeviceExt;
224 ULONG ReturnedReadLength = 0;
226 PIRP Irp;
228
229 DPRINT("NtfsRead(IrpContext %p)\n", IrpContext);
230
231 DeviceObject = IrpContext->DeviceObject;
232 Irp = IrpContext->Irp;
233 Stack = IrpContext->Stack;
234 FileObject = IrpContext->FileObject;
235
236 DeviceExt = DeviceObject->DeviceExtension;
237 ReadLength = Stack->Parameters.Read.Length;
238 ReadOffset = Stack->Parameters.Read.ByteOffset;
240
241 Status = NtfsReadFile(DeviceExt,
243 Buffer,
245 ReadOffset.u.LowPart,
246 Irp->Flags,
247 &ReturnedReadLength);
248 if (NT_SUCCESS(Status))
249 {
250 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
251 {
252 FileObject->CurrentByteOffset.QuadPart =
253 ReadOffset.QuadPart + ReturnedReadLength;
254 }
255
256 Irp->IoStatus.Information = ReturnedReadLength;
257 }
258 else
259 {
260 Irp->IoStatus.Information = 0;
261 }
262
263 return Status;
264}
ULONG ReadLength
PVOID NtfsGetUserBuffer(PIRP Irp, BOOLEAN Paging)
Definition: misc.c:120
static NTSTATUS NtfsReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PUCHAR Buffer, ULONG Length, ULONG ReadOffset, ULONG IrpFlags, PULONG LengthRead)
Definition: rw.c:43
_Must_inspect_result_ _In_ WDFUSBPIPE _In_ WDFREQUEST _In_opt_ WDFMEMORY _In_opt_ PWDFMEMORY_OFFSET ReadOffset
Definition: wdfusb.h:2003
#define IRP_PAGING_IO
#define FO_SYNCHRONOUS_IO
Definition: iotypes.h:1776

◆ NtfsReadDisk()

NTSTATUS NtfsReadDisk ( IN PDEVICE_OBJECT  DeviceObject,
IN LONGLONG  StartingOffset,
IN ULONG  Length,
IN ULONG  SectorSize,
IN OUT PUCHAR  Buffer,
IN BOOLEAN  Override 
)

Definition at line 37 of file blockdev.c.

43{
48 PIRP Irp;
50 ULONGLONG RealReadOffset;
51 ULONG RealLength;
52 BOOLEAN AllocatedBuffer = FALSE;
54
55 DPRINT("NtfsReadDisk(%p, %I64x, %lu, %lu, %p, %d)\n", DeviceObject, StartingOffset, Length, SectorSize, Buffer, Override);
56
59 FALSE);
60
61 RealReadOffset = (ULONGLONG)StartingOffset;
62 RealLength = Length;
63
64 if ((RealReadOffset % SectorSize) != 0 || (RealLength % SectorSize) != 0)
65 {
66 RealReadOffset = ROUND_DOWN(StartingOffset, SectorSize);
67 RealLength = ROUND_UP(Length, SectorSize);
68
70 if (ReadBuffer == NULL)
71 {
72 DPRINT1("Not enough memory!\n");
74 }
75 AllocatedBuffer = TRUE;
76 }
77
78 Offset.QuadPart = RealReadOffset;
79
80 DPRINT("Building synchronous FSD Request...\n");
84 RealLength,
85 &Offset,
86 &Event,
87 &IoStatus);
88 if (Irp == NULL)
89 {
90 DPRINT("IoBuildSynchronousFsdRequest failed\n");
91
92 if (AllocatedBuffer)
93 {
95 }
96
98 }
99
100 if (Override)
101 {
104 }
105
106 DPRINT("Calling IO Driver... with irp %p\n", Irp);
108
109 DPRINT("Waiting for IO Operation for %p\n", Irp);
110 if (Status == STATUS_PENDING)
111 {
112 DPRINT("Operation pending\n");
114 DPRINT("Getting IO Status... for %p\n", Irp);
115 Status = IoStatus.Status;
116 }
117
118 if (AllocatedBuffer)
119 {
120 if (NT_SUCCESS(Status))
121 {
122 RtlCopyMemory(Buffer, ReadBuffer + (StartingOffset - RealReadOffset), Length);
123 }
124
126 }
127
128 DPRINT("NtfsReadDisk() done (Status %x)\n", Status);
129
130 return Status;
131}
#define ReadBuffer(BaseIoAddress, Buffer, Count)
Definition: atapi.h:339
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:291
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:33
PIRP NTAPI IoBuildSynchronousFsdRequest(IN ULONG MajorFunction, IN PDEVICE_OBJECT DeviceObject, IN PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER StartingOffset, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock)
Definition: irp.c:1069
_In_ ULONG SectorSize
Definition: halfuncs.h:291

Referenced by NtfsReadSectors(), NtfsWriteDisk(), and ReadAttribute().

◆ NtfsReadFCBAttribute()

NTSTATUS NtfsReadFCBAttribute ( PNTFS_VCB  Vcb,
PNTFS_FCB  pFCB,
ULONG  Type,
PCWSTR  Name,
ULONG  NameLength,
PVOID Data 
)

Definition at line 735 of file fcb.c.

741{
743 PFILE_RECORD_HEADER FileRecord;
744 PNTFS_ATTR_CONTEXT AttrCtxt;
745 ULONGLONG AttrLength;
746
747 FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
748 if (FileRecord == NULL)
749 {
751 }
752
753 Status = ReadFileRecord(Vcb, pFCB->MFTIndex, FileRecord);
754 if (!NT_SUCCESS(Status))
755 {
756 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
757 return Status;
758 }
759
760 Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt, NULL);
761 if (!NT_SUCCESS(Status))
762 {
763 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
764 return Status;
765 }
766
767 AttrLength = AttributeDataLength(AttrCtxt->pRecord);
769 if (*Data == NULL)
770 {
771 ReleaseAttributeContext(AttrCtxt);
772 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
774 }
775
776 ReadAttribute(Vcb, AttrCtxt, 0, *Data, AttrLength);
777
778 ReleaseAttributeContext(AttrCtxt);
779 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
780
781 return STATUS_SUCCESS;
782}

Referenced by NtfsCreateFile().

◆ NtfsReadSectors()

NTSTATUS NtfsReadSectors ( IN PDEVICE_OBJECT  DeviceObject,
IN ULONG  DiskSector,
IN ULONG  SectorCount,
IN ULONG  SectorSize,
IN OUT PUCHAR  Buffer,
IN BOOLEAN  Override 
)

Definition at line 308 of file blockdev.c.

314{
316 ULONG BlockSize;
317
318 Offset = (LONGLONG)DiskSector * (LONGLONG)SectorSize;
319 BlockSize = SectorCount * SectorSize;
320
321 return NtfsReadDisk(DeviceObject, Offset, BlockSize, SectorSize, Buffer, Override);
322}
NTSTATUS NtfsReadDisk(IN PDEVICE_OBJECT DeviceObject, IN LONGLONG StartingOffset, IN ULONG Length, IN ULONG SectorSize, IN OUT PUCHAR Buffer, IN BOOLEAN Override)
Definition: blockdev.c:37
ULONG SectorCount
Definition: part_xbox.c:31

Referenced by NtfsGetVolumeData(), NtfsHasFileSystem(), and ReadLCN().

◆ NtfsReleaseFCB()

VOID NtfsReleaseFCB ( PNTFS_VCB  Vcb,
PNTFS_FCB  Fcb 
)

Definition at line 182 of file fcb.c.

184{
185 KIRQL oldIrql;
186
187 DPRINT("releasing FCB at %p: %S, refCount:%d\n",
188 Fcb,
189 Fcb->PathName,
190 Fcb->RefCount);
191
192 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
193 Fcb->RefCount--;
194 if (Fcb->RefCount <= 0 && !NtfsFCBIsDirectory(Fcb))
195 {
197 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
200 }
201 else
202 {
203 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
204 }
205}
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
BOOLEAN NTAPI CcUninitializeCacheMap(IN PFILE_OBJECT FileObject, IN OPTIONAL PLARGE_INTEGER TruncateSize, IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent)
Definition: fssup.c:286
VOID NtfsDestroyFCB(PNTFS_FCB Fcb)
Definition: fcb.c:120

Referenced by NtfsCloseFile(), NtfsGetFCBForFile(), and NtfsOpenFile().

◆ NtfsRelLazyWrite()

VOID NTAPI NtfsRelLazyWrite ( PVOID  Context)

Definition at line 51 of file fastio.c.

Referenced by DriverEntry().

◆ NtfsRelReadAhead()

VOID NTAPI NtfsRelReadAhead ( PVOID  Context)

Definition at line 72 of file fastio.c.

Referenced by DriverEntry().

◆ NtfsSetEndOfFile()

NTSTATUS NtfsSetEndOfFile ( PNTFS_FCB  Fcb,
PFILE_OBJECT  FileObject,
PDEVICE_EXTENSION  DeviceExt,
ULONG  IrpFlags,
BOOLEAN  CaseSensitive,
PLARGE_INTEGER  NewFileSize 
)

Definition at line 563 of file finfo.c.

569{
570 LARGE_INTEGER CurrentFileSize;
571 PFILE_RECORD_HEADER FileRecord;
572 PNTFS_ATTR_CONTEXT DataContext;
573 ULONG AttributeOffset;
576 PFILENAME_ATTRIBUTE FileNameAttribute;
577 ULONGLONG ParentMFTId;
579
580
581 // Allocate non-paged memory for the file record
582 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
583 if (FileRecord == NULL)
584 {
585 DPRINT1("Couldn't allocate memory for file record!");
587 }
588
589 // read the file record
590 DPRINT("Reading file record...\n");
591 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
592 if (!NT_SUCCESS(Status))
593 {
594 // We couldn't get the file's record. Free the memory and return the error
595 DPRINT1("Can't find record for %wS!\n", Fcb->ObjectName);
596 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
597 return Status;
598 }
599
600 DPRINT("Found record for %wS\n", Fcb->ObjectName);
601
602 CurrentFileSize.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, NULL);
603
604 // Are we trying to decrease the file size?
605 if (NewFileSize->QuadPart < CurrentFileSize.QuadPart)
606 {
607 // Is the file mapped?
608 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer,
610 {
611 DPRINT1("Couldn't decrease file size!\n");
612 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
614 }
615 }
616
617 // Find the attribute with the data stream for our file
618 DPRINT("Finding Data Attribute...\n");
619 Status = FindAttribute(DeviceExt,
620 FileRecord,
622 Fcb->Stream,
623 wcslen(Fcb->Stream),
624 &DataContext,
625 &AttributeOffset);
626
627 // Did we fail to find the attribute?
628 if (!NT_SUCCESS(Status))
629 {
630 DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
631 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
632 return Status;
633 }
634
635 // Get the size of the data attribute
636 CurrentFileSize.QuadPart = AttributeDataLength(DataContext->pRecord);
637
638 // Are we enlarging the attribute?
639 if (NewFileSize->QuadPart > CurrentFileSize.QuadPart)
640 {
641 // is increasing the stream size not allowed?
642 if ((Fcb->Flags & FCB_IS_VOLUME) ||
643 (IrpFlags & IRP_PAGING_IO))
644 {
645 // TODO - just fail for now
646 ReleaseAttributeContext(DataContext);
647 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
649 }
650 }
651
652 // set the attribute data length
653 Status = SetAttributeDataLength(FileObject, Fcb, DataContext, AttributeOffset, FileRecord, NewFileSize);
654 if (!NT_SUCCESS(Status))
655 {
656 ReleaseAttributeContext(DataContext);
657 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
658 return Status;
659 }
660
661 // now we need to update this file's size in every directory index entry that references it
662 // TODO: expand to work with every filename / hardlink stored in the file record.
663 FileNameAttribute = GetBestFileNameFromRecord(Fcb->Vcb, FileRecord);
664 if (FileNameAttribute == NULL)
665 {
666 DPRINT1("Unable to find FileName attribute associated with file!\n");
667 ReleaseAttributeContext(DataContext);
668 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
670 }
671
672 ParentMFTId = FileNameAttribute->DirectoryFileReferenceNumber & NTFS_MFT_MASK;
673
674 FileName.Buffer = FileNameAttribute->Name;
675 FileName.Length = FileNameAttribute->NameLength * sizeof(WCHAR);
676 FileName.MaximumLength = FileName.Length;
677
678 AllocationSize = AttributeAllocatedLength(DataContext->pRecord);
679
681 ParentMFTId,
682 &FileName,
683 FALSE,
686 CaseSensitive);
687
688 ReleaseAttributeContext(DataContext);
689 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
690
691 return Status;
692}
#define FCB_IS_VOLUME
Definition: ntfs.h:510
IN PFCB IN PFILE_OBJECT FileObject IN ULONG AllocationSize
Definition: fatprocs.h:322
NTSTATUS UpdateFileNameRecord(PDEVICE_EXTENSION Vcb, ULONGLONG ParentMFTIndex, PUNICODE_STRING FileName, BOOLEAN DirSearch, ULONGLONG NewDataSize, ULONGLONG NewAllocationSize, BOOLEAN CaseSensitive)
Definition: mft.c:1660
NTSTATUS SetAttributeDataLength(PFILE_OBJECT FileObject, PNTFS_FCB Fcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:615
#define STATUS_USER_MAPPED_FILE
Definition: ntstatus.h:711
BOOLEAN NTAPI MmCanFileBeTruncated(_In_ PSECTION_OBJECT_POINTERS SectionObjectPointer, _In_opt_ PLARGE_INTEGER NewFileSize)
Definition: section.c:4255
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
_In_opt_ PLARGE_INTEGER NewFileSize
Definition: mmfuncs.h:608

Referenced by NtfsSetInformation().

◆ NtfsSetInformation()

NTSTATUS NtfsSetInformation ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 719 of file finfo.c.

720{
723 PDEVICE_EXTENSION DeviceExt;
726 PVOID SystemBuffer;
728 PIRP Irp;
731
732 DPRINT("NtfsSetInformation(%p)\n", IrpContext);
733
734 Irp = IrpContext->Irp;
735 Stack = IrpContext->Stack;
736 DeviceObject = IrpContext->DeviceObject;
737 DeviceExt = DeviceObject->DeviceExtension;
738 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass;
739 FileObject = IrpContext->FileObject;
740 Fcb = FileObject->FsContext;
741
742 SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
743 BufferLength = Stack->Parameters.QueryFile.Length;
744
747 {
748 return NtfsMarkIrpContextForQueue(IrpContext);
749 }
750
751 switch (FileInformationClass)
752 {
753 PFILE_END_OF_FILE_INFORMATION EndOfFileInfo;
754
755 /* TODO: Allocation size is not actually the same as file end for NTFS,
756 however, few applications are likely to make the distinction. */
758 DPRINT1("FIXME: Using hacky method of setting FileAllocationInformation.\n");
760 EndOfFileInfo = (PFILE_END_OF_FILE_INFORMATION)SystemBuffer;
763 DeviceExt,
764 Irp->Flags,
766 &EndOfFileInfo->EndOfFile);
767 break;
768
769 // TODO: all other information classes
770
771 default:
772 DPRINT1("FIXME: Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass));
774 }
775
777
778 if (NT_SUCCESS(Status))
779 Irp->IoStatus.Information =
780 Stack->Parameters.QueryFile.Length - BufferLength;
781 else
782 Irp->IoStatus.Information = 0;
783
784 return Status;
785}
@ FileEndOfFileInformation
Definition: from_kernel.h:81
@ FileAllocationInformation
Definition: from_kernel.h:80
struct _FILE_END_OF_FILE_INFORMATION * PFILE_END_OF_FILE_INFORMATION
NTSTATUS NtfsSetEndOfFile(PNTFS_FCB Fcb, PFILE_OBJECT FileObject, PDEVICE_EXTENSION DeviceExt, ULONG IrpFlags, BOOLEAN CaseSensitive, PLARGE_INTEGER NewFileSize)
Definition: finfo.c:563
#define SL_CASE_SENSITIVE
Definition: iotypes.h:1820

Referenced by NtfsDispatch().

◆ NtfsSetVolumeInformation()

NTSTATUS NtfsSetVolumeInformation ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 420 of file volinfo.c.

421{
422 PIRP Irp;
423
424 DPRINT("NtfsSetVolumeInformation() called\n");
425
426 ASSERT(IrpContext);
427
428 Irp = IrpContext->Irp;
430 Irp->IoStatus.Information = 0;
431
433}

Referenced by NtfsDispatch().

◆ NtfsWrite()

NTSTATUS NtfsWrite ( PNTFS_IRP_CONTEXT  IrpContext)

Definition at line 537 of file rw.c.

538{
544 ULONG Length = 0;
545 ULONG ReturnedWriteLength = 0;
547 PDEVICE_EXTENSION DeviceExt = NULL;
549 PIRP Irp = NULL;
550 ULONG BytesPerSector;
551
552 DPRINT("NtfsWrite(IrpContext %p)\n", IrpContext);
553 ASSERT(IrpContext);
554
555 // get the I/O request packet
556 Irp = IrpContext->Irp;
557
558 // This request is not allowed on the main device object
559 if (IrpContext->DeviceObject == NtfsGlobalData->DeviceObject)
560 {
561 DPRINT1("\t\t\t\tNtfsWrite is called with the main device object.\n");
562
563 Irp->IoStatus.Information = 0;
565 }
566
567 // get the File control block
568 Fcb = (PNTFS_FCB)IrpContext->FileObject->FsContext;
569 ASSERT(Fcb);
570
571 DPRINT("About to write %wS\n", Fcb->ObjectName);
572 DPRINT("NTFS Version: %d.%d\n", Fcb->Vcb->NtfsInfo.MajorVersion, Fcb->Vcb->NtfsInfo.MinorVersion);
573
574 // setup some more locals
575 FileObject = IrpContext->FileObject;
576 DeviceObject = IrpContext->DeviceObject;
577 DeviceExt = DeviceObject->DeviceExtension;
578 BytesPerSector = DeviceExt->StorageDevice->SectorSize;
579 Length = IrpContext->Stack->Parameters.Write.Length;
580
581 // get the file offset we'll be writing to
582 ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
583 if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE &&
584 ByteOffset.u.HighPart == -1)
585 {
586 ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart;
587 }
588
589 DPRINT("ByteOffset: %I64u\tLength: %lu\tBytes per sector: %lu\n", ByteOffset.QuadPart,
590 Length, BytesPerSector);
591
592 if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
593 {
594 // TODO: Support large files
595 DPRINT1("FIXME: Writing to large files is not yet supported at this time.\n");
597 }
598
599 // Is this a non-cached write? A non-buffered write?
600 if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME) ||
601 IrpContext->FileObject->Flags & FILE_NO_INTERMEDIATE_BUFFERING)
602 {
603 // non-cached and non-buffered writes must be sector aligned
604 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
605 {
606 DPRINT1("Non-cached writes and non-buffered writes must be sector aligned!\n");
608 }
609 }
610
611 if (Length == 0)
612 {
613 DPRINT1("Null write!\n");
614
615 IrpContext->Irp->IoStatus.Information = 0;
616
617 // FIXME: Doesn't accurately detect when a user passes NULL to WriteFile() for the buffer
618 if (Irp->UserBuffer == NULL && Irp->MdlAddress == NULL)
619 {
620 // FIXME: Update last write time
621 return STATUS_SUCCESS;
622 }
623
625 }
626
627 // get the Resource
628 if (Fcb->Flags & FCB_IS_VOLUME)
629 {
630 Resource = &DeviceExt->DirResource;
631 }
632 else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
633 {
635 }
636 else
637 {
639 }
640
641 // acquire exclusive access to the Resource
643 {
644 return STATUS_CANT_WAIT;
645 }
646
647 /* From VfatWrite(). Todo: Handle file locks
648 if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
649 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
650 {
651 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
652 {
653 Status = STATUS_FILE_LOCK_CONFLICT;
654 goto ByeBye;
655 }
656 }*/
657
658 // Is this an async request to a file?
659 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
660 {
661 DPRINT1("FIXME: Async writes not supported in NTFS!\n");
662
665 }
666
667 // get the buffer of data the user is trying to write
669 ASSERT(Buffer);
670
671 // lock the buffer
673
674 // were we unable to lock the buffer?
675 if (!NT_SUCCESS(Status))
676 {
677 DPRINT1("Unable to lock user buffer!\n");
678
680 return Status;
681 }
682
683 DPRINT("Existing File Size(Fcb->RFCB.FileSize.QuadPart): %I64u\n", Fcb->RFCB.FileSize.QuadPart);
684 DPRINT("About to write the data. Length: %lu\n", Length);
685
686 // TODO: handle HighPart of ByteOffset (large files)
687
688 // write the file
689 Status = NtfsWriteFile(DeviceExt,
691 Buffer,
692 Length,
693 ByteOffset.LowPart,
694 Irp->Flags,
696 &ReturnedWriteLength);
697
698 IrpContext->Irp->IoStatus.Status = Status;
699
700 // was the write successful?
701 if (NT_SUCCESS(Status))
702 {
703 // TODO: Update timestamps
704
705 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
706 {
707 // advance the file pointer
708 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + ReturnedWriteLength;
709 }
710
711 IrpContext->PriorityBoost = IO_DISK_INCREMENT;
712 }
713 else
714 {
715 DPRINT1("Write not Succesful!\tReturned length: %lu\n", ReturnedWriteLength);
716 }
717
718 Irp->IoStatus.Information = ReturnedWriteLength;
719
720 // Note: We leave the user buffer that we locked alone, it's up to the I/O manager to unlock and free it
721
723
724 return Status;
725}
_Acquires_exclusive_lock_ Resource _Acquires_shared_lock_ Resource _Inout_ PERESOURCE Resource
Definition: cdprocs.h:843
NTSTATUS NtfsLockUserBuffer(IN PIRP Irp, IN ULONG Length, IN LOCK_OPERATION Operation)
Definition: misc.c:158
NTSTATUS NtfsWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, const PUCHAR Buffer, ULONG Length, ULONG WriteOffset, ULONG IrpFlags, BOOLEAN CaseSensitive, PULONG LengthWritten)
Definition: rw.c:311
ERESOURCE * PERESOURCE
Definition: env_spec_w32.h:595
#define FILE_WRITE_TO_END_OF_FILE
Definition: ext2fs.h:278
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:731
#define FILE_NO_INTERMEDIATE_BUFFERING
Definition: from_kernel.h:28
#define STATUS_CANT_WAIT
Definition: ntstatus.h:452
ERESOURCE PagingIoResource
Definition: ntfs.h:527
union _IO_STACK_LOCATION::@1564 Parameters
struct _IO_STACK_LOCATION::@3978::@3983 Write
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
#define IRP_NOCACHE
@ IoReadAccess
Definition: ketypes.h:863

Referenced by NtfsDispatch().

◆ NtfsWriteDisk()

NTSTATUS NtfsWriteDisk ( IN PDEVICE_OBJECT  DeviceObject,
IN LONGLONG  StartingOffset,
IN ULONG  Length,
IN ULONG  SectorSize,
IN const PUCHAR  Buffer 
)

Definition at line 163 of file blockdev.c.

168{
172 PIRP Irp;
174 ULONGLONG RealWriteOffset;
175 ULONG RealLength;
176 BOOLEAN AllocatedBuffer = FALSE;
177 PUCHAR TempBuffer = NULL;
178
179 DPRINT("NtfsWriteDisk(%p, %I64x, %lu, %lu, %p)\n", DeviceObject, StartingOffset, Length, SectorSize, Buffer);
180
181 if (Length == 0)
182 return STATUS_SUCCESS;
183
184 RealWriteOffset = (ULONGLONG)StartingOffset;
185 RealLength = Length;
186
187 // Does the write need to be adjusted to be sector-aligned?
188 if ((RealWriteOffset % SectorSize) != 0 || (RealLength % SectorSize) != 0)
189 {
190 ULONGLONG relativeOffset;
191
192 // We need to do a read-modify-write. We'll start be copying the entire
193 // contents of every sector that will be overwritten.
194 // TODO: Optimize (read no more than necessary)
195
196 RealWriteOffset = ROUND_DOWN(StartingOffset, SectorSize);
197 RealLength = ROUND_UP(Length, SectorSize);
198
199 // Would the end of our sector-aligned write fall short of the requested write?
200 if (RealWriteOffset + RealLength < StartingOffset + Length)
201 {
202 RealLength += SectorSize;
203 }
204
205 // Did we underestimate the memory required somehow?
206 if (RealLength + RealWriteOffset < StartingOffset + Length)
207 {
208 DPRINT1("\a\t\t\t\t\tFIXME: calculated less memory than needed!\n");
209 DPRINT1("StartingOffset: %lu\tLength: %lu\tRealWriteOffset: %lu\tRealLength: %lu\n",
210 StartingOffset, Length, RealWriteOffset, RealLength);
211
212 RealLength += SectorSize;
213 }
214
215 // Allocate a buffer to copy the existing data to
216 TempBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength, TAG_NTFS);
217
218 // Did we fail to allocate it?
219 if (TempBuffer == NULL)
220 {
221 DPRINT1("Not enough memory!\n");
222
224 }
225
226 // Read the sectors we'll be overwriting into TempBuffer
227 Status = NtfsReadDisk(DeviceObject, RealWriteOffset, RealLength, SectorSize, TempBuffer, FALSE);
228
229 // Did we fail the read?
230 if (!NT_SUCCESS(Status))
231 {
232 RtlSecureZeroMemory(TempBuffer, RealLength);
233 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
234 return Status;
235 }
236
237 // Calculate where the new data should be written to, relative to the start of TempBuffer
238 relativeOffset = StartingOffset - RealWriteOffset;
239
240 // Modify the tempbuffer with the data being read
241 RtlCopyMemory(TempBuffer + relativeOffset, Buffer, Length);
242
243 AllocatedBuffer = TRUE;
244 }
245
246 // set the destination offset
247 Offset.QuadPart = RealWriteOffset;
248
249 // setup the notification event for the write
252 FALSE);
253
254 DPRINT("Building synchronous FSD Request...\n");
255
256 // Build an IRP requesting the lower-level [disk] driver to perform the write
257 // TODO: Forward the existing IRP instead
260 // if we allocated a temp buffer, use that instead of the Buffer parameter
261 ((AllocatedBuffer) ? TempBuffer : Buffer),
262 RealLength,
263 &Offset,
264 &Event,
265 &IoStatus);
266 // Did we fail to build the IRP?
267 if (Irp == NULL)
268 {
269 DPRINT1("IoBuildSynchronousFsdRequest failed\n");
270
271 if (AllocatedBuffer)
272 {
273 RtlSecureZeroMemory(TempBuffer, RealLength);
274 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
275 }
276
278 }
279
280 // Call the next-lower driver to perform the write
281 DPRINT("Calling IO Driver with irp %p\n", Irp);
283
284 // Wait until the next-lower driver has completed the IRP
285 DPRINT("Waiting for IO Operation for %p\n", Irp);
286 if (Status == STATUS_PENDING)
287 {
288 DPRINT("Operation pending\n");
290 DPRINT("Getting IO Status... for %p\n", Irp);
291 Status = IoStatus.Status;
292 }
293
294 if (AllocatedBuffer)
295 {
296 // zero the buffer before freeing it, so private user data can't be snooped
297 RtlSecureZeroMemory(TempBuffer, RealLength);
298
299 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
300 }
301
302 DPRINT("NtfsWriteDisk() done (Status %x)\n", Status);
303
304 return Status;
305}
FORCEINLINE PVOID RtlSecureZeroMemory(_Out_writes_bytes_all_(Size) PVOID Pointer, _In_ SIZE_T Size)
Definition: rtlfuncs.h:3125

Referenced by WriteAttribute().

◆ PrepareAttributeContext()

PNTFS_ATTR_CONTEXT PrepareAttributeContext ( PNTFS_ATTR_RECORD  AttrRecord)

Definition at line 41 of file mft.c.

42{
44
45 Context = ExAllocateFromNPagedLookasideList(&NtfsGlobalData->AttrCtxtLookasideList);
46 if(!Context)
47 {
48 DPRINT1("Error: Unable to allocate memory for context!\n");
49 return NULL;
50 }
51
52 // Allocate memory for a copy of the attribute
54 if(!Context->pRecord)
55 {
56 DPRINT1("Error: Unable to allocate memory for attribute record!\n");
57 ExFreeToNPagedLookasideList(&NtfsGlobalData->AttrCtxtLookasideList, Context);
58 return NULL;
59 }
60
61 // Copy the attribute
62 RtlCopyMemory(Context->pRecord, AttrRecord, AttrRecord->Length);
63
64 if (AttrRecord->IsNonResident)
65 {
66 LONGLONG DataRunOffset;
67 ULONGLONG DataRunLength;
68 ULONGLONG NextVBN = 0;
69 PUCHAR DataRun = (PUCHAR)((ULONG_PTR)Context->pRecord + Context->pRecord->NonResident.MappingPairsOffset);
70
71 Context->CacheRun = DataRun;
72 Context->CacheRunOffset = 0;
73 Context->CacheRun = DecodeRun(Context->CacheRun, &DataRunOffset, &DataRunLength);
74 Context->CacheRunLength = DataRunLength;
75 if (DataRunOffset != -1)
76 {
77 /* Normal run. */
78 Context->CacheRunStartLCN =
79 Context->CacheRunLastLCN = DataRunOffset;
80 }
81 else
82 {
83 /* Sparse run. */
84 Context->CacheRunStartLCN = -1;
85 Context->CacheRunLastLCN = 0;
86 }
87 Context->CacheRunCurrentOffset = 0;
88
89 // Convert the data runs to a map control block
90 if (!NT_SUCCESS(ConvertDataRunsToLargeMCB(DataRun, &Context->DataRunsMCB, &NextVBN)))
91 {
92 DPRINT1("Unable to convert data runs to MCB!\n");
94 ExFreeToNPagedLookasideList(&NtfsGlobalData->AttrCtxtLookasideList, Context);
95 return NULL;
96 }
97 }
98
99 return Context;
100}
NTSTATUS ConvertDataRunsToLargeMCB(PUCHAR DataRun, PLARGE_MCB DataRunsMCB, PULONGLONG pNextVBN)
Definition: attrib.c:825
NPAGED_LOOKASIDE_LIST AttrCtxtLookasideList
Definition: ntfs.h:154

Referenced by FindAttribute(), and InternalReadNonResidentAttributes().

◆ ReadAttribute()

ULONG ReadAttribute ( PDEVICE_EXTENSION  Vcb,
PNTFS_ATTR_CONTEXT  Context,
ULONGLONG  Offset,
PCHAR  Buffer,
ULONG  Length 
)

Definition at line 1065 of file mft.c.

1070{
1071 ULONGLONG LastLCN;
1072 PUCHAR DataRun;
1073 LONGLONG DataRunOffset;
1074 ULONGLONG DataRunLength;
1075 LONGLONG DataRunStartLCN;
1076 ULONGLONG CurrentOffset;
1078 ULONG AlreadyRead;
1080
1081 //TEMPTEMP
1082 PUCHAR TempBuffer;
1083
1084 if (!Context->pRecord->IsNonResident)
1085 {
1086 // We need to truncate Offset to a ULONG for pointer arithmetic
1087 // The check below should ensure that Offset is well within the range of 32 bits
1088 ULONG LittleOffset = (ULONG)Offset;
1089
1090 // Ensure that offset isn't beyond the end of the attribute
1091 if (Offset > Context->pRecord->Resident.ValueLength)
1092 return 0;
1093 if (Offset + Length > Context->pRecord->Resident.ValueLength)
1094 Length = (ULONG)(Context->pRecord->Resident.ValueLength - Offset);
1095
1096 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Context->pRecord + Context->pRecord->Resident.ValueOffset + LittleOffset), Length);
1097 return Length;
1098 }
1099
1100 /*
1101 * Non-resident attribute
1102 */
1103
1104 /*
1105 * I. Find the corresponding start data run.
1106 */
1107
1108 AlreadyRead = 0;
1109
1110 // FIXME: Cache seems to be non-working. Disable it for now
1111 //if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * Volume->ClusterSize)
1112 if (0)
1113 {
1114 DataRun = Context->CacheRun;
1115 LastLCN = Context->CacheRunLastLCN;
1116 DataRunStartLCN = Context->CacheRunStartLCN;
1117 DataRunLength = Context->CacheRunLength;
1118 CurrentOffset = Context->CacheRunCurrentOffset;
1119 }
1120 else
1121 {
1122 //TEMPTEMP
1123 ULONG UsedBufferSize;
1124 TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
1125 if (TempBuffer == NULL)
1126 {
1128 }
1129
1130 LastLCN = 0;
1131 CurrentOffset = 0;
1132
1133 // This will be rewritten in the next iteration to just use the DataRuns MCB directly
1134 ConvertLargeMCBToDataRuns(&Context->DataRunsMCB,
1135 TempBuffer,
1136 Vcb->NtfsInfo.BytesPerFileRecord,
1137 &UsedBufferSize);
1138
1139 DataRun = TempBuffer;
1140
1141 while (1)
1142 {
1143 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1144 if (DataRunOffset != -1)
1145 {
1146 /* Normal data run. */
1147 DataRunStartLCN = LastLCN + DataRunOffset;
1148 LastLCN = DataRunStartLCN;
1149 }
1150 else
1151 {
1152 /* Sparse data run. */
1153 DataRunStartLCN = -1;
1154 }
1155
1156 if (Offset >= CurrentOffset &&
1157 Offset < CurrentOffset + (DataRunLength * Vcb->NtfsInfo.BytesPerCluster))
1158 {
1159 break;
1160 }
1161
1162 if (*DataRun == 0)
1163 {
1164 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
1165 return AlreadyRead;
1166 }
1167
1168 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1169 }
1170 }
1171
1172 /*
1173 * II. Go through the run list and read the data
1174 */
1175
1176 ReadLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset), Length);
1177 if (DataRunStartLCN == -1)
1178 {
1181 }
1182 else
1183 {
1184 Status = NtfsReadDisk(Vcb->StorageDevice,
1185 DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster + Offset - CurrentOffset,
1186 ReadLength,
1187 Vcb->NtfsInfo.BytesPerSector,
1188 (PVOID)Buffer,
1189 FALSE);
1190 }
1191 if (NT_SUCCESS(Status))
1192 {
1193 Length -= ReadLength;
1194 Buffer += ReadLength;
1195 AlreadyRead += ReadLength;
1196
1197 if (ReadLength == DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset))
1198 {
1199 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1200 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1201 if (DataRunOffset != (ULONGLONG)-1)
1202 {
1203 DataRunStartLCN = LastLCN + DataRunOffset;
1204 LastLCN = DataRunStartLCN;
1205 }
1206 else
1207 DataRunStartLCN = -1;
1208 }
1209
1210 while (Length > 0)
1211 {
1212 ReadLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster, Length);
1213 if (DataRunStartLCN == -1)
1215 else
1216 {
1217 Status = NtfsReadDisk(Vcb->StorageDevice,
1218 DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster,
1219 ReadLength,
1220 Vcb->NtfsInfo.BytesPerSector,
1221 (PVOID)Buffer,
1222 FALSE);
1223 if (!NT_SUCCESS(Status))
1224 break;
1225 }
1226
1227 Length -= ReadLength;
1228 Buffer += ReadLength;
1229 AlreadyRead += ReadLength;
1230
1231 /* We finished this request, but there still data in this data run. */
1232 if (Length == 0 && ReadLength != DataRunLength * Vcb->NtfsInfo.BytesPerCluster)
1233 break;
1234
1235 /*
1236 * Go to next run in the list.
1237 */
1238
1239 if (*DataRun == 0)
1240 break;
1241 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1242 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1243 if (DataRunOffset != -1)
1244 {
1245 /* Normal data run. */
1246 DataRunStartLCN = LastLCN + DataRunOffset;
1247 LastLCN = DataRunStartLCN;
1248 }
1249 else
1250 {
1251 /* Sparse data run. */
1252 DataRunStartLCN = -1;
1253 }
1254 } /* while */
1255
1256 } /* if Disk */
1257
1258 // TEMPTEMP
1259 if (Context->pRecord->IsNonResident)
1260 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
1261
1262 Context->CacheRun = DataRun;
1263 Context->CacheRunOffset = Offset + AlreadyRead;
1264 Context->CacheRunStartLCN = DataRunStartLCN;
1265 Context->CacheRunLength = DataRunLength;
1266 Context->CacheRunLastLCN = LastLCN;
1267 Context->CacheRunCurrentOffset = CurrentOffset;
1268
1269 return AlreadyRead;
1270}

Referenced by AddNewMftEntry(), AllocateIndexNode(), BrowseIndexEntries(), BrowseSubNodeIndexEntries(), CreateBTreeNodeFromIndexNode(), FreeClusters(), GetVolumeBitmap(), IncreaseMftSize(), InternalReadNonResidentAttributes(), NtfsAddFilenameToDirectory(), NtfsAllocateClusters(), NtfsFindMftRecord(), NtfsGetFreeClusters(), NtfsReadFCBAttribute(), NtfsReadFile(), PrintAllVCNs(), ReadFileRecord(), SetResidentAttributeDataLength(), UpdateFileNameRecord(), UpdateIndexEntryFileNameSize(), and UpdateMftMirror().

◆ ReadFileRecord()

NTSTATUS ReadFileRecord ( PDEVICE_EXTENSION  Vcb,
ULONGLONG  index,
PFILE_RECORD_HEADER  file 
)

Definition at line 1631 of file mft.c.

1634{
1636
1637 DPRINT("ReadFileRecord(%p, %I64x, %p)\n", Vcb, index, file);
1638
1639 BytesRead = ReadAttribute(Vcb, Vcb->MFTContext, index * Vcb->NtfsInfo.BytesPerFileRecord, (PCHAR)file, Vcb->NtfsInfo.BytesPerFileRecord);
1640 if (BytesRead != Vcb->NtfsInfo.BytesPerFileRecord)
1641 {
1642 DPRINT1("ReadFileRecord failed: %I64u read, %lu expected\n", BytesRead, Vcb->NtfsInfo.BytesPerFileRecord);
1643 return STATUS_PARTIAL_COPY;
1644 }
1645
1646 /* Apply update sequence array fixups. */
1647 DPRINT("Sequence number: %u\n", file->SequenceNumber);
1648 return FixupUpdateSequenceArray(Vcb, &file->Ntfs);
1649}
GLuint index
Definition: glext.h:6031
NTSTATUS FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:1965
#define STATUS_PARTIAL_COPY
Definition: ntstatus.h:193
Definition: fci.c:127
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870

Referenced by FindAttribute(), FreeClusters(), GetNtfsFileRecord(), GetVolumeBitmap(), NtfsAddFilenameToDirectory(), NtfsAllocateClusters(), NtfsCreateFile(), NtfsFindFileAt(), NtfsFindMftRecord(), NtfsGetFreeClusters(), NtfsGetStreamInformation(), NtfsGetVolumeData(), NtfsLookupFileAt(), NtfsMakeRootFCB(), NtfsMoonWalkID(), NtfsOpenFileById(), NtfsReadFCBAttribute(), NtfsReadFile(), NtfsSetEndOfFile(), NtfsWriteFile(), UpdateFileNameRecord(), UpdateMftMirror(), and WriteAttribute().

◆ ReadLCN()

NTSTATUS ReadLCN ( PDEVICE_EXTENSION  Vcb,
ULONGLONG  lcn,
ULONG  count,
PVOID  buffer 
)

Definition at line 2631 of file mft.c.

2635{
2636 LARGE_INTEGER DiskSector;
2637
2638 DiskSector.QuadPart = lcn;
2639
2640 return NtfsReadSectors(Vcb->StorageDevice,
2641 DiskSector.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
2642 count * Vcb->NtfsInfo.SectorsPerCluster,
2643 Vcb->NtfsInfo.BytesPerSector,
2644 buffer,
2645 FALSE);
2646}
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint buffer
Definition: glext.h:5915
NTSTATUS NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject, IN ULONG DiskSector, IN ULONG SectorCount, IN ULONG SectorSize, IN OUT PUCHAR Buffer, IN BOOLEAN Override)
Definition: blockdev.c:308
struct _LARGE_INTEGER::@2295 u

◆ ReadVCN()

VOID ReadVCN ( PDEVICE_EXTENSION  Vcb,
PFILE_RECORD_HEADER  file,
ATTRIBUTE_TYPE  type,
ULONGLONG  vcn,
ULONG  count,
PVOID  buffer 
)

◆ ReleaseAttributeContext()

◆ SetAttributeDataLength()

NTSTATUS SetAttributeDataLength ( PFILE_OBJECT  FileObject,
PNTFS_FCB  Fcb,
PNTFS_ATTR_CONTEXT  AttrContext,
ULONG  AttrOffset,
PFILE_RECORD_HEADER  FileRecord,
PLARGE_INTEGER  DataSize 
)

@parameter FileRecord Pointer to a file record. Must be a full record at least Fcb->Vcb->NtfsInfo.BytesPerFileRecord bytes large, not just the header.

Definition at line 615 of file mft.c.

621{
623
624 DPRINT1("SetAttributeDataLength(%p, %p, %p, %lu, %p, %I64u)\n",
626 Fcb,
627 AttrContext,
628 AttrOffset,
629 FileRecord,
630 DataSize->QuadPart);
631
632 // are we truncating the file?
633 if (DataSize->QuadPart < AttributeDataLength(AttrContext->pRecord))
634 {
635 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer, DataSize))
636 {
637 DPRINT1("Can't truncate a memory-mapped file!\n");
639 }
640 }
641
642 if (AttrContext->pRecord->IsNonResident)
643 {
645 AttrContext,
646 AttrOffset,
647 FileRecord,
648 DataSize);
649 }
650 else
651 {
652 // resident attribute
654 AttrContext,
655 AttrOffset,
656 FileRecord,
657 DataSize);
658 }
659
660 if (!NT_SUCCESS(Status))
661 {
662 DPRINT1("ERROR: Failed to set size of attribute!\n");
663 return Status;
664 }
665
666 //NtfsDumpFileAttributes(Fcb->Vcb, FileRecord);
667
668 // write the updated file record back to disk
669 Status = UpdateFileRecord(Fcb->Vcb, Fcb->MFTIndex, FileRecord);
670
671 if (NT_SUCCESS(Status))
672 {
673 if (AttrContext->pRecord->IsNonResident)
674 Fcb->RFCB.AllocationSize.QuadPart = AttrContext->pRecord->NonResident.AllocatedSize;
675 else
680 }
681
682 return STATUS_SUCCESS;
683}
VOID NTAPI CcSetFileSizes(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes)
Definition: fssup.c:356
NTSTATUS SetNonResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:756
NTSTATUS SetResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:891

Referenced by NtfsCreateFile(), NtfsSetEndOfFile(), and NtfsWriteFile().

◆ SetFileRecordEnd()

VOID SetFileRecordEnd ( PFILE_RECORD_HEADER  FileRecord,
PNTFS_ATTR_RECORD  AttrEnd,
ULONG  EndMarker 
)

Definition at line 706 of file mft.c.

709{
710 // Ensure AttrEnd is aligned on an 8-byte boundary, relative to FileRecord
711 ASSERT(((ULONG_PTR)AttrEnd - (ULONG_PTR)FileRecord) % ATTR_RECORD_ALIGNMENT == 0);
712
713 // mark the end of attributes
714 AttrEnd->Type = AttributeEnd;
715
716 // Restore the "file-record-end marker." The value is never checked but this behavior is consistent with Win2k3.
717 AttrEnd->Length = EndMarker;
718
719 // recalculate bytes in use
720 FileRecord->BytesInUse = (ULONG_PTR)AttrEnd - (ULONG_PTR)FileRecord + sizeof(ULONG) * 2;
721}

Referenced by AddBitmap(), AddData(), AddFileName(), AddIndexAllocation(), AddIndexRoot(), AddRun(), AddStandardInformation(), FreeClusters(), InternalSetResidentAttributeLength(), and SetResidentAttributeDataLength().

◆ SetNonResidentAttributeDataLength()

NTSTATUS SetNonResidentAttributeDataLength ( PDEVICE_EXTENSION  Vcb,
PNTFS_ATTR_CONTEXT  AttrContext,
ULONG  AttrOffset,
PFILE_RECORD_HEADER  FileRecord,
PLARGE_INTEGER  DataSize 
)

Definition at line 756 of file mft.c.

761{
763 ULONG BytesPerCluster = Vcb->NtfsInfo.BytesPerCluster;
764 ULONGLONG AllocationSize = ROUND_UP(DataSize->QuadPart, BytesPerCluster);
765 PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
766 ULONG ExistingClusters = AttrContext->pRecord->NonResident.AllocatedSize / BytesPerCluster;
767
768 ASSERT(AttrContext->pRecord->IsNonResident);
769
770 // do we need to increase the allocation size?
771 if (AttrContext->pRecord->NonResident.AllocatedSize < AllocationSize)
772 {
773 ULONG ClustersNeeded = (AllocationSize / BytesPerCluster) - ExistingClusters;
774 LARGE_INTEGER LastClusterInDataRun;
775 ULONG NextAssignedCluster;
776 ULONG AssignedClusters;
777
778 if (ExistingClusters == 0)
779 {
780 LastClusterInDataRun.QuadPart = 0;
781 }
782 else
783 {
784 if (!FsRtlLookupLargeMcbEntry(&AttrContext->DataRunsMCB,
785 (LONGLONG)AttrContext->pRecord->NonResident.HighestVCN,
786 (PLONGLONG)&LastClusterInDataRun.QuadPart,
787 NULL,
788 NULL,
789 NULL,
790 NULL))
791 {
792 DPRINT1("Error looking up final large MCB entry!\n");
793
794 // Most likely, HighestVCN went above the largest mapping
795 DPRINT1("Highest VCN of record: %I64u\n", AttrContext->pRecord->NonResident.HighestVCN);
797 }
798 }
799
800 DPRINT("LastClusterInDataRun: %I64u\n", LastClusterInDataRun.QuadPart);
801 DPRINT("Highest VCN of record: %I64u\n", AttrContext->pRecord->NonResident.HighestVCN);
802
803 while (ClustersNeeded > 0)
804 {
806 LastClusterInDataRun.LowPart + 1,
807 ClustersNeeded,
808 &NextAssignedCluster,
809 &AssignedClusters);
810
811 if (!NT_SUCCESS(Status))
812 {
813 DPRINT1("Error: Unable to allocate requested clusters!\n");
814 return Status;
815 }
816
817 // now we need to add the clusters we allocated to the data run
818 Status = AddRun(Vcb, AttrContext, AttrOffset, FileRecord, NextAssignedCluster, AssignedClusters);
819 if (!NT_SUCCESS(Status))
820 {
821 DPRINT1("Error: Unable to add data run!\n");
822 return Status;
823 }
824
825 ClustersNeeded -= AssignedClusters;
826 LastClusterInDataRun.LowPart = NextAssignedCluster + AssignedClusters - 1;
827 }
828 }
829 else if (AttrContext->pRecord->NonResident.AllocatedSize > AllocationSize)
830 {
831 // shrink allocation size
832 ULONG ClustersToFree = ExistingClusters - (AllocationSize / BytesPerCluster);
833 Status = FreeClusters(Vcb, AttrContext, AttrOffset, FileRecord, ClustersToFree);
834 }
835
836 // TODO: is the file compressed, encrypted, or sparse?
837
838 AttrContext->pRecord->NonResident.AllocatedSize = AllocationSize;
839 AttrContext->pRecord->NonResident.DataSize = DataSize->QuadPart;
840 AttrContext->pRecord->NonResident.InitializedSize = DataSize->QuadPart;
841
842 DestinationAttribute->NonResident.AllocatedSize = AllocationSize;
843 DestinationAttribute->NonResident.DataSize = DataSize->QuadPart;
844 DestinationAttribute->NonResident.InitializedSize = DataSize->QuadPart;
845
846 // HighestVCN seems to be set incorrectly somewhere. Apply a hack-fix to reset it.
847 // HACKHACK FIXME: Fix for sparse files; this math won't work in that case.
848 AttrContext->pRecord->NonResident.HighestVCN = ((ULONGLONG)AllocationSize / Vcb->NtfsInfo.BytesPerCluster) - 1;
849 DestinationAttribute->NonResident.HighestVCN = AttrContext->pRecord->NonResident.HighestVCN;
850
851 DPRINT("Allocated Size: %I64u\n", DestinationAttribute->NonResident.AllocatedSize);
852
853 return Status;
854}
NTSTATUS AddRun(PNTFS_VCB Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, ULONGLONG NextAssignedCluster, ULONG RunLength)
Definition: attrib.c:599
NTSTATUS NtfsAllocateClusters(PDEVICE_EXTENSION DeviceExt, ULONG FirstDesiredCluster, ULONG DesiredClusters, PULONG FirstAssignedCluster, PULONG AssignedClusters)
Definition: volinfo.c:105
BOOLEAN NTAPI FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb, IN LONGLONG Vbn, OUT PLONGLONG Lbn OPTIONAL, OUT PLONGLONG SectorCountFromLbn OPTIONAL, OUT PLONGLONG StartingLbn OPTIONAL, OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL, OUT PULONG Index OPTIONAL)
Definition: largemcb.c:560
__GNU_EXTENSION typedef __int64 * PLONGLONG
Definition: ntbasedef.h:382

Referenced by AllocateIndexNode(), IncreaseMftSize(), SetAttributeDataLength(), and SetResidentAttributeDataLength().

◆ SetResidentAttributeDataLength()

NTSTATUS SetResidentAttributeDataLength ( PDEVICE_EXTENSION  Vcb,
PNTFS_ATTR_CONTEXT  AttrContext,
ULONG  AttrOffset,
PFILE_RECORD_HEADER  FileRecord,
PLARGE_INTEGER  DataSize 
)

Definition at line 891 of file mft.c.

896{
898
899 // find the next attribute
900 ULONG NextAttributeOffset = AttrOffset + AttrContext->pRecord->Length;
901 PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((PCHAR)FileRecord + NextAttributeOffset);
902
903 ASSERT(!AttrContext->pRecord->IsNonResident);
904
905 //NtfsDumpFileAttributes(Vcb, FileRecord);
906
907 // Do we need to increase the data length?
908 if (DataSize->QuadPart > AttrContext->pRecord->Resident.ValueLength)
909 {
910 // There's usually padding at the end of a record. Do we need to extend past it?
911 ULONG MaxValueLength = AttrContext->pRecord->Length - AttrContext->pRecord->Resident.ValueOffset;
912 if (MaxValueLength < DataSize->LowPart)
913 {
914 // If this is the last attribute, we could move the end marker to the very end of the file record
915 MaxValueLength += Vcb->NtfsInfo.BytesPerFileRecord - NextAttributeOffset - (sizeof(ULONG) * 2);
916
917 if (MaxValueLength < DataSize->LowPart || NextAttribute->Type != AttributeEnd)
918 {
919 // convert attribute to non-resident
920 PNTFS_ATTR_RECORD Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
921 PNTFS_ATTR_RECORD NewRecord;
922 LARGE_INTEGER AttribDataSize;
923 PVOID AttribData;
924 ULONG NewRecordLength;
925 ULONG EndAttributeOffset;
926 ULONG LengthWritten;
927
928 DPRINT1("Converting attribute to non-resident.\n");
929
930 AttribDataSize.QuadPart = AttrContext->pRecord->Resident.ValueLength;
931
932 // Is there existing data we need to back-up?
933 if (AttribDataSize.QuadPart > 0)
934 {
935 AttribData = ExAllocatePoolWithTag(NonPagedPool, AttribDataSize.QuadPart, TAG_NTFS);
936 if (AttribData == NULL)
937 {
938 DPRINT1("ERROR: Couldn't allocate memory for attribute data. Can't migrate to non-resident!\n");
940 }
941
942 // read data to temp buffer
943 Status = ReadAttribute(Vcb, AttrContext, 0, AttribData, AttribDataSize.QuadPart);
944 if (!NT_SUCCESS(Status))
945 {
946 DPRINT1("ERROR: Unable to read attribute before migrating!\n");
947 ExFreePoolWithTag(AttribData, TAG_NTFS);
948 return Status;
949 }
950 }
951
952 // Start by turning this attribute into a 0-length, non-resident attribute, then enlarge it.
953
954 // The size of a 0-length, non-resident attribute will be 0x41 + the size of the attribute name, aligned to an 8-byte boundary
955 NewRecordLength = ALIGN_UP_BY(0x41 + (AttrContext->pRecord->NameLength * sizeof(WCHAR)), ATTR_RECORD_ALIGNMENT);
956
957 // Create a new attribute record that will store the 0-length, non-resident attribute
958 NewRecord = ExAllocatePoolWithTag(NonPagedPool, NewRecordLength, TAG_NTFS);
959
960 // Zero out the NonResident structure
961 RtlZeroMemory(NewRecord, NewRecordLength);
962
963 // Copy the data that's common to both non-resident and resident attributes
964 RtlCopyMemory(NewRecord, AttrContext->pRecord, FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.ValueLength));
965
966 // if there's a name
967 if (AttrContext->pRecord->NameLength != 0)
968 {
969 // copy the name
970 // An attribute name will be located at offset 0x18 for a resident attribute, 0x40 for non-resident
971 RtlCopyMemory((PCHAR)((ULONG_PTR)NewRecord + 0x40),
972 (PCHAR)((ULONG_PTR)AttrContext->pRecord + 0x18),
973 AttrContext->pRecord->NameLength * sizeof(WCHAR));
974 }
975
976 // update the mapping pairs offset, which will be 0x40 (size of a non-resident header) + length in bytes of the name
977 NewRecord->NonResident.MappingPairsOffset = 0x40 + (AttrContext->pRecord->NameLength * sizeof(WCHAR));
978
979 // update the end of the file record
980 // calculate position of end markers (1 byte for empty data run)
981 EndAttributeOffset = AttrOffset + NewRecord->NonResident.MappingPairsOffset + 1;
982 EndAttributeOffset = ALIGN_UP_BY(EndAttributeOffset, ATTR_RECORD_ALIGNMENT);
983
984 // Update the length
985 NewRecord->Length = EndAttributeOffset - AttrOffset;
986
987 ASSERT(NewRecord->Length == NewRecordLength);
988
989 // Copy the new attribute record into the file record
990 RtlCopyMemory(Destination, NewRecord, NewRecord->Length);
991
992 // Update the file record end
993 SetFileRecordEnd(FileRecord,
994 (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + EndAttributeOffset),
996
997 // Initialize the MCB, potentially catch an exception
999 {
1000 FsRtlInitializeLargeMcb(&AttrContext->DataRunsMCB, NonPagedPool);
1001 }
1003 {
1004 DPRINT1("Unable to create LargeMcb!\n");
1005 if (AttribDataSize.QuadPart > 0)
1006 ExFreePoolWithTag(AttribData, TAG_NTFS);
1007 ExFreePoolWithTag(NewRecord, TAG_NTFS);
1009 } _SEH2_END;
1010
1011 // Mark the attribute as non-resident (we wait until after we know the LargeMcb was initialized)
1012 NewRecord->IsNonResident = Destination->IsNonResident = 1;
1013
1014 // Update file record on disk
1015 Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord);
1016 if (!NT_SUCCESS(Status))
1017 {
1018 DPRINT1("ERROR: Couldn't update file record to continue migration!\n");
1019 if (AttribDataSize.QuadPart > 0)
1020 ExFreePoolWithTag(AttribData, TAG_NTFS);
1021 ExFreePoolWithTag(NewRecord, TAG_NTFS);
1022 return Status;
1023 }
1024
1025 // Now we need to free the old copy of the attribute record in the context and replace it with the new one
1026 ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS);
1027 AttrContext->pRecord = NewRecord;
1028
1029 // Now we can treat the attribute as non-resident and enlarge it normally
1030 Status = SetNonResidentAttributeDataLength(Vcb, AttrContext, AttrOffset, FileRecord, DataSize);
1031 if (!NT_SUCCESS(Status))
1032 {
1033 DPRINT1("ERROR: Unable to migrate resident attribute!\n");
1034 if (AttribDataSize.QuadPart > 0)
1035 ExFreePoolWithTag(AttribData, TAG_NTFS);
1036 return Status;
1037 }
1038
1039 // restore the back-up attribute, if we made one
1040 if (AttribDataSize.QuadPart > 0)
1041 {
1042 Status = WriteAttribute(Vcb, AttrContext, 0, AttribData, AttribDataSize.QuadPart, &LengthWritten, FileRecord);
1043 if (!NT_SUCCESS(Status))
1044 {
1045 DPRINT1("ERROR: Unable to write attribute data to non-resident clusters during migration!\n");
1046 // TODO: Reverse migration so no data is lost
1047 ExFreePoolWithTag(AttribData, TAG_NTFS);
1048 return Status;
1049 }
1050
1051 ExFreePoolWithTag(AttribData, TAG_NTFS);
1052 }
1053 }
1054 }
1055 }
1056
1057 // set the new length of the resident attribute (if we didn't migrate it)
1058 if (!AttrContext->pRecord->IsNonResident)
1059 return InternalSetResidentAttributeLength(Vcb, AttrContext, FileRecord, AttrOffset, DataSize->LowPart);
1060
1061 return STATUS_SUCCESS;
1062}
ULONG ValueLength
Definition: ntfs.h:138

Referenced by AllocateIndexNode(), IncreaseMftSize(), and SetAttributeDataLength().

◆ SplitBTreeNode()

NTSTATUS SplitBTreeNode ( PB_TREE  Tree,
PB_TREE_FILENAME_NODE  Node,
PB_TREE_KEY MedianKey,
PB_TREE_FILENAME_NODE NewRightHandSibling,
BOOLEAN  CaseSensitive 
)

Definition at line 1883 of file btree.c.

1888{
1889 ULONG MedianKeyIndex;
1890 PB_TREE_KEY LastKeyBeforeMedian, FirstKeyAfterMedian;
1891 ULONG KeyCount;
1892 ULONG HalfSize;
1893 ULONG SizeSum;
1894 ULONG i;
1895
1896 DPRINT("SplitBTreeNode(%p, %p, %p, %p, %s) called\n",
1897 Tree,
1898 Node,
1899 MedianKey,
1900 NewRightHandSibling,
1901 CaseSensitive ? "TRUE" : "FALSE");
1902
1903#ifndef NDEBUG
1904 DumpBTreeNode(Tree, Node, 0, 0);
1905#endif
1906
1907 // Create the right hand sibling
1908 *NewRightHandSibling = ExAllocatePoolWithTag(NonPagedPool, sizeof(B_TREE_FILENAME_NODE), TAG_NTFS);
1909 if (*NewRightHandSibling == NULL)
1910 {
1911 DPRINT1("Error: Failed to allocate memory for right hand sibling!\n");
1913 }
1914 RtlZeroMemory(*NewRightHandSibling, sizeof(B_TREE_FILENAME_NODE));
1915 (*NewRightHandSibling)->DiskNeedsUpdating = TRUE;
1916
1917
1918 // Find the last key before the median
1919
1920 // This is roughly how NTFS-3G calculates median, and it's not congruent with what Windows does:
1921 /*
1922 // find the median key index
1923 MedianKeyIndex = (Node->KeyCount + 1) / 2;
1924 MedianKeyIndex--;
1925
1926 LastKeyBeforeMedian = Node->FirstKey;
1927 for (i = 0; i < MedianKeyIndex - 1; i++)
1928 LastKeyBeforeMedian = LastKeyBeforeMedian->NextKey;*/
1929
1930 // The method we'll use is a little bit closer to how Windows determines the median but it's not identical.
1931 // What Windows does is actually more complicated than this, I think because Windows allocates more slack space to Odd-numbered
1932 // Index Records, leaving less room for index entries in these records (I haven't discovered why this is done).
1933 // (Neither Windows nor chkdsk complain if we choose a different median than Windows would have chosen, as our median will be in the ballpark)
1934
1935 // Use size to locate the median key / index
1936 LastKeyBeforeMedian = Node->FirstKey;
1937 MedianKeyIndex = 0;
1938 HalfSize = 2016; // half the allocated size after subtracting the first index entry offset (TODO: MATH)
1939 SizeSum = 0;
1940 for (i = 0; i < Node->KeyCount; i++)
1941 {
1942 SizeSum += LastKeyBeforeMedian->IndexEntry->Length;
1943
1944 if (SizeSum > HalfSize)
1945 break;
1946
1947 MedianKeyIndex++;
1948 LastKeyBeforeMedian = LastKeyBeforeMedian->NextKey;
1949 }
1950
1951 // Now we can get the median key and the key that follows it
1952 *MedianKey = LastKeyBeforeMedian->NextKey;
1953 FirstKeyAfterMedian = (*MedianKey)->NextKey;
1954
1955 DPRINT1("%lu keys, %lu median\n", Node->KeyCount, MedianKeyIndex);
1956 DPRINT1("\t\tMedian: %.*S\n", (*MedianKey)->IndexEntry->FileName.NameLength, (*MedianKey)->IndexEntry->FileName.Name);
1957
1958 // "Node" will be the left hand sibling after the split, containing all keys prior to the median key
1959
1960 // We need to create a dummy pointer at the end of the LHS. The dummy's child will be the median's child.
1961 LastKeyBeforeMedian->NextKey = CreateDummyKey(BooleanFlagOn((*MedianKey)->IndexEntry->Flags, NTFS_INDEX_ENTRY_NODE));
1962 if (LastKeyBeforeMedian->NextKey == NULL)
1963 {
1964 DPRINT1("Error: Couldn't allocate dummy key!\n");
1965 LastKeyBeforeMedian->NextKey = *MedianKey;
1966 ExFreePoolWithTag(*NewRightHandSibling, TAG_NTFS);
1968 }
1969
1970 // Did the median key have a child node?
1971 if ((*MedianKey)->IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
1972 {
1973 // Set the child of the new dummy key
1974 LastKeyBeforeMedian->NextKey->LesserChild = (*MedianKey)->LesserChild;
1975
1976 // Give the dummy key's index entry the same sub-node VCN the median
1977 SetIndexEntryVCN(LastKeyBeforeMedian->NextKey->IndexEntry, GetIndexEntryVCN((*MedianKey)->IndexEntry));
1978 }
1979 else
1980 {
1981 // Median key didn't have a child node, but it will. Create a new index entry large enough to store a VCN.
1983 (*MedianKey)->IndexEntry->Length + sizeof(ULONGLONG),
1984 TAG_NTFS);
1985 if (!NewIndexEntry)
1986 {
1987 DPRINT1("Unable to allocate memory for new index entry!\n");
1988 LastKeyBeforeMedian->NextKey = *MedianKey;
1989 ExFreePoolWithTag(*NewRightHandSibling, TAG_NTFS);
1991 }
1992
1993 // Copy the old index entry to the new one
1994 RtlCopyMemory(NewIndexEntry, (*MedianKey)->IndexEntry, (*MedianKey)->IndexEntry->Length);
1995
1996 // Use the new index entry after freeing the old one
1997 ExFreePoolWithTag((*MedianKey)->IndexEntry, TAG_NTFS);
1998 (*MedianKey)->IndexEntry = NewIndexEntry;
1999
2000 // Update the length for the VCN
2001 (*MedianKey)->IndexEntry->Length += sizeof(ULONGLONG);
2002
2003 // Set the node flag
2004 (*MedianKey)->IndexEntry->Flags |= NTFS_INDEX_ENTRY_NODE;
2005 }
2006
2007 // "Node" will become the child of the median key
2008 (*MedianKey)->LesserChild = Node;
2009 SetIndexEntryVCN((*MedianKey)->IndexEntry, Node->VCN);
2010
2011 // Update Node's KeyCount (remember to add 1 for the new dummy key)
2012 Node->KeyCount = MedianKeyIndex + 2;
2013
2014 KeyCount = CountBTreeKeys(Node->FirstKey);
2015 ASSERT(Node->KeyCount == KeyCount);
2016
2017 // everything to the right of MedianKey becomes the right hand sibling of Node
2018 (*NewRightHandSibling)->FirstKey = FirstKeyAfterMedian;
2019 (*NewRightHandSibling)->KeyCount = CountBTreeKeys(FirstKeyAfterMedian);
2020
2021#ifndef NDEBUG
2022 DPRINT1("Left-hand node after split:\n");
2023 DumpBTreeNode(Tree, Node, 0, 0);
2024
2025 DPRINT1("Right-hand sibling node after split:\n");
2026 DumpBTreeNode(Tree, *NewRightHandSibling, 0, 0);
2027#endif
2028
2029 return STATUS_SUCCESS;
2030}
ULONG CountBTreeKeys(PB_TREE_KEY FirstKey)
Definition: btree.c:484
ULONGLONG GetIndexEntryVCN(PINDEX_ENTRY_ATTRIBUTE IndexEntry)
Definition: btree.c:1641
VOID SetIndexEntryVCN(PINDEX_ENTRY_ATTRIBUTE IndexEntry, ULONGLONG VCN)
Definition: btree.c:1172
union node Node
Definition: types.h:1255

Referenced by NtfsInsertKey().

◆ UpdateFileNameRecord()

NTSTATUS UpdateFileNameRecord ( PDEVICE_EXTENSION  Vcb,
ULONGLONG  ParentMFTIndex,
PUNICODE_STRING  FileName,
BOOLEAN  DirSearch,
ULONGLONG  NewDataSize,
ULONGLONG  NewAllocationSize,
BOOLEAN  CaseSensitive 
)

Searches a file's parent directory (given the parent's index in the mft) for the given file. Upon finding an index entry for that file, updates Data Size and Allocated Size values in the $FILE_NAME attribute of that entry.

(Most of this code was copied from NtfsFindMftRecord)

Definition at line 1660 of file mft.c.

1667{
1668 PFILE_RECORD_HEADER MftRecord;
1669 PNTFS_ATTR_CONTEXT IndexRootCtx;
1670 PINDEX_ROOT_ATTRIBUTE IndexRoot;
1671 PCHAR IndexRecord;
1672 PINDEX_ENTRY_ATTRIBUTE IndexEntry, IndexEntryEnd;
1674 ULONG CurrentEntry = 0;
1675
1676 DPRINT("UpdateFileNameRecord(%p, %I64d, %wZ, %s, %I64u, %I64u, %s)\n",
1677 Vcb,
1678 ParentMFTIndex,
1679 FileName,
1680 DirSearch ? "TRUE" : "FALSE",
1681 NewDataSize,
1682 NewAllocationSize,
1683 CaseSensitive ? "TRUE" : "FALSE");
1684
1685 MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
1686 if (MftRecord == NULL)
1687 {
1689 }
1690
1691 Status = ReadFileRecord(Vcb, ParentMFTIndex, MftRecord);
1692 if (!NT_SUCCESS(Status))
1693 {
1694 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1695 return Status;
1696 }
1697
1698 ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
1699 Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
1700 if (!NT_SUCCESS(Status))
1701 {
1702 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1703 return Status;
1704 }
1705
1706 IndexRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerIndexRecord, TAG_NTFS);
1707 if (IndexRecord == NULL)
1708 {
1709 ReleaseAttributeContext(IndexRootCtx);
1710 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1712 }
1713
1714 Status = ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, AttributeDataLength(IndexRootCtx->pRecord));
1715 if (!NT_SUCCESS(Status))
1716 {
1717 DPRINT1("ERROR: Failed to read Index Root!\n");
1718 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
1719 ReleaseAttributeContext(IndexRootCtx);
1720 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1721 return Status;
1722 }
1723
1724 IndexRoot = (PINDEX_ROOT_ATTRIBUTE)IndexRecord;
1725 IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)&IndexRoot->Header + IndexRoot->Header.FirstEntryOffset);
1726 // Index root is always resident.
1727 IndexEntryEnd = (PINDEX_ENTRY_ATTRIBUTE)(IndexRecord + IndexRoot->Header.TotalSizeOfEntries);
1728
1729 DPRINT("IndexRecordSize: %x IndexBlockSize: %x\n", Vcb->NtfsInfo.BytesPerIndexRecord, IndexRoot->SizeOfEntry);
1730
1732 MftRecord,
1733 IndexRecord,
1734 IndexRoot->SizeOfEntry,
1735 IndexEntry,
1736 IndexEntryEnd,
1737 FileName,
1738 &CurrentEntry,
1739 &CurrentEntry,
1740 DirSearch,
1741 NewDataSize,
1742 NewAllocationSize,
1743 CaseSensitive);
1744
1745 if (Status == STATUS_PENDING)
1746 {
1747 // we need to write the index root attribute back to disk
1748 ULONG LengthWritten;
1749 Status = WriteAttribute(Vcb, IndexRootCtx, 0, (PUCHAR)IndexRecord, AttributeDataLength(IndexRootCtx->pRecord), &LengthWritten, MftRecord);
1750 if (!NT_SUCCESS(Status))
1751 {
1752 DPRINT1("ERROR: Couldn't update Index Root!\n");
1753 }
1754
1755 }
1756
1757 ReleaseAttributeContext(IndexRootCtx);
1758 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
1759 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1760
1761 return Status;
1762}
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)
Definition: mft.c:1770

Referenced by NtfsSetEndOfFile(), and NtfsWriteFile().

◆ UpdateFileRecord()

NTSTATUS UpdateFileRecord ( PDEVICE_EXTENSION  Vcb,
ULONGLONG  MftIndex,
PFILE_RECORD_HEADER  FileRecord 
)

Definition at line 1931 of file mft.c.

1934{
1937
1938 DPRINT("UpdateFileRecord(%p, 0x%I64x, %p)\n", Vcb, MftIndex, FileRecord);
1939
1940 // Add the fixup array to prepare the data for writing to disk
1941 AddFixupArray(Vcb, &FileRecord->Ntfs);
1942
1943 // write the file record to the master file table
1945 Vcb->MFTContext,
1946 MftIndex * Vcb->NtfsInfo.BytesPerFileRecord,
1947 (const PUCHAR)FileRecord,
1948 Vcb->NtfsInfo.BytesPerFileRecord,
1949 &BytesWritten,
1950 FileRecord);
1951
1952 if (!NT_SUCCESS(Status))
1953 {
1954 DPRINT1("UpdateFileRecord failed: %lu written, %lu expected\n", BytesWritten, Vcb->NtfsInfo.BytesPerFileRecord);
1955 }
1956
1957 // remove the fixup array (so the file record pointer can still be used)
1958 FixupUpdateSequenceArray(Vcb, &FileRecord->Ntfs);
1959
1960 return Status;
1961}
NTSTATUS AddFixupArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:2603
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:960

Referenced by AddNewMftEntry(), AddRun(), AllocateIndexNode(), FreeClusters(), IncreaseMftSize(), NtfsAddFilenameToDirectory(), SetAttributeDataLength(), SetResidentAttributeDataLength(), and WriteAttribute().

◆ UpdateIndexAllocation()

NTSTATUS UpdateIndexAllocation ( PDEVICE_EXTENSION  DeviceExt,
PB_TREE  Tree,
ULONG  IndexBufferSize,
PFILE_RECORD_HEADER  FileRecord 
)

Definition at line 1182 of file btree.c.

1186{
1187 // Find the index allocation and bitmap
1188 PNTFS_ATTR_CONTEXT IndexAllocationContext;
1189 PB_TREE_KEY CurrentKey;
1191 BOOLEAN HasIndexAllocation = FALSE;
1192 ULONG i;
1193 ULONG IndexAllocationOffset;
1194
1195 DPRINT("UpdateIndexAllocation() called.\n");
1196
1197 Status = FindAttribute(DeviceExt, FileRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationContext, &IndexAllocationOffset);
1198 if (NT_SUCCESS(Status))
1199 {
1200 HasIndexAllocation = TRUE;
1201
1202#ifndef NDEBUG
1203 PrintAllVCNs(DeviceExt,
1204 IndexAllocationContext,
1205 IndexBufferSize);
1206#endif
1207 }
1208 // Walk through the root node and update all the sub-nodes
1209 CurrentKey = Tree->RootNode->FirstKey;
1210 for (i = 0; i < Tree->RootNode->KeyCount; i++)
1211 {
1212 if (CurrentKey->LesserChild)
1213 {
1214 if (!HasIndexAllocation)
1215 {
1216 // We need to add an index allocation to the file record
1217 PNTFS_ATTR_RECORD EndMarker = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse - (sizeof(ULONG) * 2));
1218 DPRINT1("Adding index allocation...\n");
1219
1220 // Add index allocation to the very end of the file record
1221 Status = AddIndexAllocation(DeviceExt,
1222 FileRecord,
1223 EndMarker,
1224 L"$I30",
1225 4);
1226 if (!NT_SUCCESS(Status))
1227 {
1228 DPRINT1("ERROR: Failed to add index allocation!\n");
1229 return Status;
1230 }
1231
1232 // Find the new attribute
1233 Status = FindAttribute(DeviceExt, FileRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationContext, &IndexAllocationOffset);
1234 if (!NT_SUCCESS(Status))
1235 {
1236 DPRINT1("ERROR: Couldn't find newly-created index allocation!\n");
1237 return Status;
1238 }
1239
1240 // Advance end marker
1241 EndMarker = (PNTFS_ATTR_RECORD)((ULONG_PTR)EndMarker + EndMarker->Length);
1242
1243 // Add index bitmap to the very end of the file record
1244 Status = AddBitmap(DeviceExt,
1245 FileRecord,
1246 EndMarker,
1247 L"$I30",
1248 4);
1249 if (!NT_SUCCESS(Status))
1250 {
1251 DPRINT1("ERROR: Failed to add index bitmap!\n");
1252 ReleaseAttributeContext(IndexAllocationContext);
1253 return Status;
1254 }
1255
1256 HasIndexAllocation = TRUE;
1257 }
1258
1259 // Is the Index Entry large enough to store the VCN?
1261 {
1262 // Allocate memory for the larger index entry
1264 CurrentKey->IndexEntry->Length + sizeof(ULONGLONG),
1265 TAG_NTFS);
1266 if (!NewEntry)
1267 {
1268 DPRINT1("ERROR: Unable to allocate memory for new index entry!\n");
1269 if (HasIndexAllocation)
1270 ReleaseAttributeContext(IndexAllocationContext);
1272 }
1273
1274 // Copy the old entry to the new one
1275 RtlCopyMemory(NewEntry, CurrentKey->IndexEntry, CurrentKey->IndexEntry->Length);
1276
1277 NewEntry->Length += sizeof(ULONGLONG);
1278
1279 // Free the old memory
1281
1282 CurrentKey->IndexEntry = NewEntry;
1283 CurrentKey->IndexEntry->Flags |= NTFS_INDEX_ENTRY_NODE;
1284 }
1285
1286 // Update the sub-node
1287 Status = UpdateIndexNode(DeviceExt, FileRecord, CurrentKey->LesserChild, IndexBufferSize, IndexAllocationContext, IndexAllocationOffset);
1288 if (!NT_SUCCESS(Status))
1289 {
1290 DPRINT1("ERROR: Failed to update index node!\n");
1291 ReleaseAttributeContext(IndexAllocationContext);
1292 return Status;
1293 }
1294
1295 // Update the VCN stored in the index entry of CurrentKey
1296 SetIndexEntryVCN(CurrentKey->IndexEntry, CurrentKey->LesserChild->VCN);
1297 }
1298 CurrentKey = CurrentKey->NextKey;
1299 }
1300
1301#ifndef NDEBUG
1302 DumpBTree(Tree);
1303#endif
1304
1305 if (HasIndexAllocation)
1306 {
1307#ifndef NDEBUG
1308 PrintAllVCNs(DeviceExt,
1309 IndexAllocationContext,
1310 IndexBufferSize);
1311#endif
1312 ReleaseAttributeContext(IndexAllocationContext);
1313 }
1314
1315 return STATUS_SUCCESS;
1316}
VOID PrintAllVCNs(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT IndexAllocationContext, ULONG NodeSize)
Definition: btree.c:38
NTSTATUS UpdateIndexNode(PDEVICE_EXTENSION DeviceExt, PFILE_RECORD_HEADER FileRecord, PB_TREE_FILENAME_NODE Node, ULONG IndexBufferSize, PNTFS_ATTR_CONTEXT IndexAllocationContext, ULONG IndexAllocationOffset)
Definition: btree.c:1319
NTSTATUS AddBitmap(PNTFS_VCB Vcb, PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress, PCWSTR Name, USHORT NameLength)
Definition: attrib.c:72
NTSTATUS AddIndexAllocation(PNTFS_VCB Vcb, PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttributeAddress, PCWSTR Name, USHORT NameLength)
Definition: attrib.c:388
ULONGLONG VCN
Definition: ntfs.h:449

Referenced by NtfsAddFilenameToDirectory().

◆ UpdateIndexEntryFileNameSize()

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 
)

Recursively searches directory index and applies the size update to the $FILE_NAME attribute of the proper index entry. (Heavily based on BrowseIndexEntries)

Definition at line 1770 of file mft.c.

1783{
1785 ULONG RecordOffset;
1786 PINDEX_ENTRY_ATTRIBUTE IndexEntry;
1787 PNTFS_ATTR_CONTEXT IndexAllocationCtx;
1788 ULONGLONG IndexAllocationSize;
1789 PINDEX_BUFFER IndexBuffer;
1790
1791 DPRINT("UpdateIndexEntrySize(%p, %p, %p, %lu, %p, %p, %wZ, %lu, %lu, %s, %I64u, %I64u, %s)\n",
1792 Vcb,
1793 MftRecord,
1794 IndexRecord,
1795 IndexBlockSize,
1796 FirstEntry,
1797 LastEntry,
1798 FileName,
1799 *StartEntry,
1800 *CurrentEntry,
1801 DirSearch ? "TRUE" : "FALSE",
1802 NewDataSize,
1803 NewAllocatedSize,
1804 CaseSensitive ? "TRUE" : "FALSE");
1805
1806 // find the index entry responsible for the file we're trying to update
1807 IndexEntry = FirstEntry;
1808 while (IndexEntry < LastEntry &&
1809 !(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
1810 {
1811 if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) > NTFS_FILE_FIRST_USER_FILE &&
1812 *CurrentEntry >= *StartEntry &&
1813 IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
1814 CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
1815 {
1816 *StartEntry = *CurrentEntry;
1817 IndexEntry->FileName.DataSize = NewDataSize;
1818 IndexEntry->FileName.AllocatedSize = NewAllocatedSize;
1819 // indicate that the caller will still need to write the structure to the disk
1820 return STATUS_PENDING;
1821 }
1822
1823 (*CurrentEntry) += 1;
1824 ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
1825 IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
1826 }
1827
1828 /* If we're already browsing a subnode */
1829 if (IndexRecord == NULL)
1830 {
1832 }
1833
1834 /* If there's no subnode */
1835 if (!(IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE))
1836 {
1838 }
1839
1840 Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationCtx, NULL);
1841 if (!NT_SUCCESS(Status))
1842 {
1843 DPRINT("Corrupted filesystem!\n");
1844 return Status;
1845 }
1846
1847 IndexAllocationSize = AttributeDataLength(IndexAllocationCtx->pRecord);
1849 for (RecordOffset = 0; RecordOffset < IndexAllocationSize; RecordOffset += IndexBlockSize)
1850 {
1851 ReadAttribute(Vcb, IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
1852 Status = FixupUpdateSequenceArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
1853 if (!NT_SUCCESS(Status))
1854 {
1855 break;
1856 }
1857
1858 IndexBuffer = (PINDEX_BUFFER)IndexRecord;
1859 ASSERT(IndexBuffer->Ntfs.Type == NRH_INDX_TYPE);
1860 ASSERT(IndexBuffer->Header.AllocatedSize + FIELD_OFFSET(INDEX_BUFFER, Header) == IndexBlockSize);
1861 FirstEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.FirstEntryOffset);
1862 LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.TotalSizeOfEntries);
1863 ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexBuffer + IndexBlockSize));
1864
1866 NULL,
1867 NULL,
1868 0,
1869 FirstEntry,
1870 LastEntry,
1871 FileName,
1872 StartEntry,
1873 CurrentEntry,
1874 DirSearch,
1875 NewDataSize,
1876 NewAllocatedSize,
1877 CaseSensitive);
1878 if (Status == STATUS_PENDING)
1879 {
1880 // write the index record back to disk
1881 ULONG Written;
1882
1883 // first we need to update the fixup values for the index block
1884 Status = AddFixupArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
1885 if (!NT_SUCCESS(Status))
1886 {
1887 DPRINT1("Error: Failed to update fixup sequence array!\n");
1888 break;
1889 }
1890
1891 Status = WriteAttribute(Vcb, IndexAllocationCtx, RecordOffset, (const PUCHAR)IndexRecord, IndexBlockSize, &Written, MftRecord);
1892 if (!NT_SUCCESS(Status))
1893 {
1894 DPRINT1("ERROR Performing write!\n");
1895 break;
1896 }
1897
1899 break;
1900 }
1901 if (NT_SUCCESS(Status))
1902 {
1903 break;
1904 }
1905 }
1906
1907 ReleaseAttributeContext(IndexAllocationCtx);
1908 return Status;
1909}
struct INDEX_BUFFER * PINDEX_BUFFER
#define NTFS_FILE_FIRST_USER_FILE
Definition: ntfs.h:196
#define NRH_INDX_TYPE
Definition: ntfs.h:247
BOOLEAN CompareFileName(PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive)
Definition: mft.c:2650
ULONGLONG DataSize
Definition: ntfs.h:366
ULONGLONG AllocatedSize
Definition: ntfs.h:365
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:405
NTFS_RECORD_HEADER Ntfs
Definition: ntfs.h:403
struct INDEX_ENTRY_ATTRIBUTE::@763::@764 Directory
union INDEX_ENTRY_ATTRIBUTE::@763 Data

Referenced by UpdateFileNameRecord(), and UpdateIndexEntryFileNameSize().

◆ UpdateIndexNode()

NTSTATUS UpdateIndexNode ( PDEVICE_EXTENSION  DeviceExt,
PFILE_RECORD_HEADER  FileRecord,
PB_TREE_FILENAME_NODE  Node,
ULONG  IndexBufferSize,
PNTFS_ATTR_CONTEXT  IndexAllocationContext,
ULONG  IndexAllocationOffset 
)

Definition at line 1319 of file btree.c.

1325{
1326 ULONG i;
1327 PB_TREE_KEY CurrentKey = Node->FirstKey;
1328 BOOLEAN HasChildren = FALSE;
1330
1331
1332 DPRINT("UpdateIndexNode(%p, %p, %p, %lu, %p, %lu) called for index node with VCN %I64u\n",
1333 DeviceExt,
1334 FileRecord,
1335 Node,
1336 IndexBufferSize,
1337 IndexAllocationContext,
1338 IndexAllocationOffset,
1339 Node->VCN);
1340
1341 // Walk through the node and look for children to update
1342 for (i = 0; i < Node->KeyCount; i++)
1343 {
1344 ASSERT(CurrentKey);
1345
1346 // If there's a child node
1347 if (CurrentKey->LesserChild)
1348 {
1349 HasChildren = TRUE;
1350
1351 // Update the child node on disk
1352 Status = UpdateIndexNode(DeviceExt, FileRecord, CurrentKey->LesserChild, IndexBufferSize, IndexAllocationContext, IndexAllocationOffset);
1353 if (!NT_SUCCESS(Status))
1354 {
1355 DPRINT1("ERROR: Failed to update child node!\n");
1356 return Status;
1357 }
1358
1359 // Is the Index Entry large enough to store the VCN?
1361 {
1362 // Allocate memory for the larger index entry
1364 CurrentKey->IndexEntry->Length + sizeof(ULONGLONG),
1365 TAG_NTFS);
1366 if (!NewEntry)
1367 {
1368 DPRINT1("ERROR: Unable to allocate memory for new index entry!\n");
1370 }
1371
1372 // Copy the old entry to the new one
1373 RtlCopyMemory(NewEntry, CurrentKey->IndexEntry, CurrentKey->IndexEntry->Length);
1374
1375 NewEntry->Length += sizeof(ULONGLONG);
1376
1377 // Free the old memory
1379
1380 CurrentKey->IndexEntry = NewEntry;
1381 }
1382
1383 // Update the VCN stored in the index entry of CurrentKey
1384 SetIndexEntryVCN(CurrentKey->IndexEntry, CurrentKey->LesserChild->VCN);
1385
1386 CurrentKey->IndexEntry->Flags |= NTFS_INDEX_ENTRY_NODE;
1387 }
1388
1389 CurrentKey = CurrentKey->NextKey;
1390 }
1391
1392
1393 // Do we need to write this node to disk?
1394 if (Node->DiskNeedsUpdating)
1395 {
1396 ULONGLONG NodeOffset;
1397 ULONG LengthWritten;
1398 PINDEX_BUFFER IndexBuffer;
1399
1400 // Does the node need to be assigned a VCN?
1401 if (!Node->HasValidVCN)
1402 {
1403 // Allocate the node
1404 Status = AllocateIndexNode(DeviceExt,
1405 FileRecord,
1406 IndexBufferSize,
1407 IndexAllocationContext,
1408 IndexAllocationOffset,
1409 &Node->VCN);
1410 if (!NT_SUCCESS(Status))
1411 {
1412 DPRINT1("ERROR: Failed to allocate index record in index allocation!\n");
1413 return Status;
1414 }
1415
1416 Node->HasValidVCN = TRUE;
1417 }
1418
1419 // Allocate memory for an index buffer
1420 IndexBuffer = ExAllocatePoolWithTag(NonPagedPool, IndexBufferSize, TAG_NTFS);
1421 if (!IndexBuffer)
1422 {
1423 DPRINT1("ERROR: Failed to allocate %lu bytes for index buffer!\n", IndexBufferSize);
1425 }
1426
1427 // Create the index buffer we'll be writing to disk to represent this node
1428 Status = CreateIndexBufferFromBTreeNode(DeviceExt, Node, IndexBufferSize, HasChildren, IndexBuffer);
1429 if (!NT_SUCCESS(Status))
1430 {
1431 DPRINT1("ERROR: Failed to create index buffer from node!\n");
1432 ExFreePoolWithTag(IndexBuffer, TAG_NTFS);
1433 return Status;
1434 }
1435
1436 // Get Offset of index buffer in index allocation
1437 NodeOffset = GetAllocationOffsetFromVCN(DeviceExt, IndexBufferSize, Node->VCN);
1438
1439 // Write the buffer to the index allocation
1440 Status = WriteAttribute(DeviceExt, IndexAllocationContext, NodeOffset, (const PUCHAR)IndexBuffer, IndexBufferSize, &LengthWritten, FileRecord);
1441 if (!NT_SUCCESS(Status) || LengthWritten != IndexBufferSize)
1442 {
1443 DPRINT1("ERROR: Failed to update index allocation!\n");
1444 ExFreePoolWithTag(IndexBuffer, TAG_NTFS);
1445 if (!NT_SUCCESS(Status))
1446 return Status;
1447 else
1448 return STATUS_END_OF_FILE;
1449 }
1450
1451 Node->DiskNeedsUpdating = FALSE;
1452
1453 // Free the index buffer
1454 ExFreePoolWithTag(IndexBuffer, TAG_NTFS);
1455 }
1456
1457 return STATUS_SUCCESS;
1458}
NTSTATUS AllocateIndexNode(PDEVICE_EXTENSION DeviceExt, PFILE_RECORD_HEADER FileRecord, ULONG IndexBufferSize, PNTFS_ATTR_CONTEXT IndexAllocationCtx, ULONG IndexAllocationOffset, PULONGLONG NewVCN)
Definition: btree.c:117
ULONGLONG GetAllocationOffsetFromVCN(PDEVICE_EXTENSION DeviceExt, ULONG IndexBufferSize, ULONGLONG Vcn)
Definition: btree.c:1630
NTSTATUS CreateIndexBufferFromBTreeNode(PDEVICE_EXTENSION DeviceExt, PB_TREE_FILENAME_NODE Node, ULONG BufferSize, BOOLEAN HasChildren, PINDEX_BUFFER IndexBuffer)
Definition: btree.c:1001

Referenced by UpdateIndexAllocation(), and UpdateIndexNode().

◆ UpdateMftMirror()

NTSTATUS UpdateMftMirror ( PNTFS_VCB  Vcb)

Definition at line 2714 of file mft.c.

2715{
2716 PFILE_RECORD_HEADER MirrorFileRecord;
2717 PNTFS_ATTR_CONTEXT MirrDataContext;
2718 PNTFS_ATTR_CONTEXT MftDataContext;
2719 PCHAR DataBuffer;
2723 ULONG LengthWritten;
2724
2725 // Allocate memory for the Mft mirror file record
2726 MirrorFileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
2727 if (!MirrorFileRecord)
2728 {
2729 DPRINT1("Error: Failed to allocate memory for $MFTMirr!\n");
2731 }
2732
2733 // Read the Mft Mirror file record
2734 Status = ReadFileRecord(Vcb, NTFS_FILE_MFTMIRR, MirrorFileRecord);
2735 if (!NT_SUCCESS(Status))
2736 {
2737 DPRINT1("ERROR: Failed to read $MFTMirr!\n");
2738 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2739 return Status;
2740 }
2741
2742 // Find the $DATA attribute of $MFTMirr
2743 Status = FindAttribute(Vcb, MirrorFileRecord, AttributeData, L"", 0, &MirrDataContext, NULL);
2744 if (!NT_SUCCESS(Status))
2745 {
2746 DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
2747 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2748 return Status;
2749 }
2750
2751 // Find the $DATA attribute of $MFT
2752 Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeData, L"", 0, &MftDataContext, NULL);
2753 if (!NT_SUCCESS(Status))
2754 {
2755 DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
2756 ReleaseAttributeContext(MirrDataContext);
2757 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2758 return Status;
2759 }
2760
2761 // Get the size of the mirror's $DATA attribute
2762 DataLength = AttributeDataLength(MirrDataContext->pRecord);
2763
2764 ASSERT(DataLength % Vcb->NtfsInfo.BytesPerFileRecord == 0);
2765
2766 // Create buffer for the mirror's $DATA attribute
2768 if (!DataBuffer)
2769 {
2770 DPRINT1("Error: Couldn't allocate memory for $DATA buffer!\n");
2771 ReleaseAttributeContext(MftDataContext);
2772 ReleaseAttributeContext(MirrDataContext);
2773 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2775 }
2776
2778
2779 // Back up the first several entries of the Mft's $DATA Attribute
2780 BytesRead = ReadAttribute(Vcb, MftDataContext, 0, DataBuffer, (ULONG)DataLength);
2781 if (BytesRead != (ULONG)DataLength)
2782 {
2783 DPRINT1("Error: Failed to read $DATA for $MFTMirr!\n");
2784 ReleaseAttributeContext(MftDataContext);
2785 ReleaseAttributeContext(MirrDataContext);
2786 ExFreePoolWithTag(DataBuffer, TAG_NTFS);
2787 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2788 return STATUS_UNSUCCESSFUL;
2789 }
2790
2791 // Write the mirror's $DATA attribute
2793 MirrDataContext,
2794 0,
2795 (PUCHAR)DataBuffer,
2796 DataLength,
2797 &LengthWritten,
2798 MirrorFileRecord);
2799 if (!NT_SUCCESS(Status))
2800 {
2801 DPRINT1("ERROR: Failed to write $DATA attribute of $MFTMirr!\n");
2802 }
2803
2804 // Cleanup
2805 ReleaseAttributeContext(MftDataContext);
2806 ReleaseAttributeContext(MirrDataContext);
2807 ExFreePoolWithTag(DataBuffer, TAG_NTFS);
2808 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2809
2810 return Status;
2811}
#define NTFS_FILE_MFTMIRR
Definition: ntfs.h:24
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1444

Referenced by IncreaseMftSize().

◆ WriteAttribute()

NTSTATUS WriteAttribute ( PDEVICE_EXTENSION  Vcb,
PNTFS_ATTR_CONTEXT  Context,
ULONGLONG  Offset,
const PUCHAR  Buffer,
ULONG  Length,
PULONG  LengthWritten,
PFILE_RECORD_HEADER  FileRecord 
)

Definition at line 1315 of file mft.c.

1322{
1323 ULONGLONG LastLCN;
1324 PUCHAR DataRun;
1325 LONGLONG DataRunOffset;
1326 ULONGLONG DataRunLength;
1327 LONGLONG DataRunStartLCN;
1328 ULONGLONG CurrentOffset;
1331 PUCHAR SourceBuffer = Buffer;
1333 BOOLEAN FileRecordAllocated = FALSE;
1334
1335 //TEMPTEMP
1336 PUCHAR TempBuffer;
1337
1338
1339 DPRINT("WriteAttribute(%p, %p, %I64u, %p, %lu, %p, %p)\n", Vcb, Context, Offset, Buffer, Length, RealLengthWritten, FileRecord);
1340
1341 *RealLengthWritten = 0;
1342
1343 // is this a resident attribute?
1344 if (!Context->pRecord->IsNonResident)
1345 {
1346 ULONG AttributeOffset;
1347 PNTFS_ATTR_CONTEXT FoundContext;
1349
1350 // Ensure requested data is within the bounds of the attribute
1351 ASSERT(Offset + Length <= Context->pRecord->Resident.ValueLength);
1352
1353 if (Offset + Length > Context->pRecord->Resident.ValueLength)
1354 {
1355 DPRINT1("DRIVER ERROR: Attribute is too small!\n");
1357 }
1358
1359 // Do we need to read the file record?
1360 if (FileRecord == NULL)
1361 {
1362 FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
1363 if (!FileRecord)
1364 {
1365 DPRINT1("Error: Couldn't allocate file record!\n");
1366 return STATUS_NO_MEMORY;
1367 }
1368
1369 FileRecordAllocated = TRUE;
1370
1371 // read the file record
1372 ReadFileRecord(Vcb, Context->FileMFTIndex, FileRecord);
1373 }
1374
1375 // find where to write the attribute data to
1376 Status = FindAttribute(Vcb, FileRecord,
1377 Context->pRecord->Type,
1378 (PCWSTR)((ULONG_PTR)Context->pRecord + Context->pRecord->NameOffset),
1379 Context->pRecord->NameLength,
1380 &FoundContext,
1381 &AttributeOffset);
1382
1383 if (!NT_SUCCESS(Status))
1384 {
1385 DPRINT1("ERROR: Couldn't find matching attribute!\n");
1386 if(FileRecordAllocated)
1387 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
1388 return Status;
1389 }
1390
1391 Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttributeOffset);
1392
1393 DPRINT("Offset: %I64u, AttributeOffset: %u, ValueOffset: %u\n", Offset, AttributeOffset, Context->pRecord->Resident.ValueLength);
1394
1395 // Will we be writing past the end of the allocated file record?
1396 if (Offset + Length + AttributeOffset + Context->pRecord->Resident.ValueOffset > Vcb->NtfsInfo.BytesPerFileRecord)
1397 {
1398 DPRINT1("DRIVER ERROR: Data being written extends past end of file record!\n");
1399 ReleaseAttributeContext(FoundContext);
1400 if (FileRecordAllocated)
1401 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
1403 }
1404
1405 // copy the data being written into the file record. We cast Offset to ULONG, which is safe because it's range has been verified.
1406 RtlCopyMemory((PCHAR)((ULONG_PTR)Destination + Context->pRecord->Resident.ValueOffset + (ULONG)Offset), Buffer, Length);
1407
1408 Status = UpdateFileRecord(Vcb, Context->FileMFTIndex, FileRecord);
1409
1410 // Update the context's copy of the resident attribute
1411 ASSERT(Context->pRecord->Length == Destination->Length);
1412 RtlCopyMemory((PVOID)Context->pRecord, Destination, Context->pRecord->Length);
1413
1414 ReleaseAttributeContext(FoundContext);
1415 if (FileRecordAllocated)
1416 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
1417
1418 if (NT_SUCCESS(Status))
1419 *RealLengthWritten = Length;
1420
1421 return Status;
1422 }
1423
1424 // This is a non-resident attribute.
1425
1426 // I. Find the corresponding start data run.
1427
1428 // FIXME: Cache seems to be non-working. Disable it for now
1429 //if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * Volume->ClusterSize)
1430 /*if (0)
1431 {
1432 DataRun = Context->CacheRun;
1433 LastLCN = Context->CacheRunLastLCN;
1434 DataRunStartLCN = Context->CacheRunStartLCN;
1435 DataRunLength = Context->CacheRunLength;
1436 CurrentOffset = Context->CacheRunCurrentOffset;
1437 }
1438 else*/
1439 {
1440 ULONG UsedBufferSize;
1441 LastLCN = 0;
1442 CurrentOffset = 0;
1443
1444 // This will be rewritten in the next iteration to just use the DataRuns MCB directly
1445 TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
1446 if (TempBuffer == NULL)
1447 {
1449 }
1450
1451 ConvertLargeMCBToDataRuns(&Context->DataRunsMCB,
1452 TempBuffer,
1453 Vcb->NtfsInfo.BytesPerFileRecord,
1454 &UsedBufferSize);
1455
1456 DataRun = TempBuffer;
1457
1458 while (1)
1459 {
1460 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1461 if (DataRunOffset != -1)
1462 {
1463 // Normal data run.
1464 // DPRINT1("Writing to normal data run, LastLCN %I64u DataRunOffset %I64d\n", LastLCN, DataRunOffset);
1465 DataRunStartLCN = LastLCN + DataRunOffset;
1466 LastLCN = DataRunStartLCN;
1467 }
1468 else
1469 {
1470 // Sparse data run. We can't support writing to sparse files yet
1471 // (it may require increasing the allocation size).
1472 DataRunStartLCN = -1;
1473 DPRINT1("FIXME: Writing to sparse files is not supported yet!\n");
1475 goto Cleanup;
1476 }
1477
1478 // Have we reached the data run we're trying to write to?
1479 if (Offset >= CurrentOffset &&
1480 Offset < CurrentOffset + (DataRunLength * Vcb->NtfsInfo.BytesPerCluster))
1481 {
1482 break;
1483 }
1484
1485 if (*DataRun == 0)
1486 {
1487 // We reached the last assigned cluster
1488 // TODO: assign new clusters to the end of the file.
1489 // (Presently, this code will rarely be reached, the write will usually have already failed by now)
1490 // [We can reach here by creating a new file record when the MFT isn't large enough]
1491 DPRINT1("FIXME: Master File Table needs to be enlarged.\n");
1493 goto Cleanup;
1494 }
1495
1496 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1497 }
1498 }
1499
1500 // II. Go through the run list and write the data
1501
1502 /* REVIEWME -- As adapted from NtfsReadAttribute():
1503 We seem to be making a special case for the first applicable data run, but I'm not sure why.
1504 Does it have something to do with (not) caching? Is this strategy equally applicable to writing? */
1505
1506 WriteLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset), Length);
1507
1508 StartingOffset = DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster + Offset - CurrentOffset;
1509
1510 // Write the data to the disk
1511 Status = NtfsWriteDisk(Vcb->StorageDevice,
1514 Vcb->NtfsInfo.BytesPerSector,
1515 (PVOID)SourceBuffer);
1516
1517 // Did the write fail?
1518 if (!NT_SUCCESS(Status))
1519 {
1520 Context->CacheRun = DataRun;
1521 Context->CacheRunOffset = Offset;
1522 Context->CacheRunStartLCN = DataRunStartLCN;
1523 Context->CacheRunLength = DataRunLength;
1524 Context->CacheRunLastLCN = LastLCN;
1525 Context->CacheRunCurrentOffset = CurrentOffset;
1526
1527 goto Cleanup;
1528 }
1529
1531 SourceBuffer += WriteLength;
1532 *RealLengthWritten += WriteLength;
1533
1534 // Did we write to the end of the data run?
1535 if (WriteLength == DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset))
1536 {
1537 // Advance to the next data run
1538 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1539 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1540
1541 if (DataRunOffset != (ULONGLONG)-1)
1542 {
1543 DataRunStartLCN = LastLCN + DataRunOffset;
1544 LastLCN = DataRunStartLCN;
1545 }
1546 else
1547 DataRunStartLCN = -1;
1548 }
1549
1550 // Do we have more data to write?
1551 while (Length > 0)
1552 {
1553 // Make sure we don't write past the end of the current data run
1554 WriteLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster, Length);
1555
1556 // Are we dealing with a sparse data run?
1557 if (DataRunStartLCN == -1)
1558 {
1559 DPRINT1("FIXME: Don't know how to write to sparse files yet! (DataRunStartLCN == -1)\n");
1561 goto Cleanup;
1562 }
1563 else
1564 {
1565 // write the data to the disk
1566 Status = NtfsWriteDisk(Vcb->StorageDevice,
1567 DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster,
1569 Vcb->NtfsInfo.BytesPerSector,
1570 (PVOID)SourceBuffer);
1571 if (!NT_SUCCESS(Status))
1572 break;
1573 }
1574
1576 SourceBuffer += WriteLength;
1577 *RealLengthWritten += WriteLength;
1578
1579 // We finished this request, but there's still data in this data run.
1580 if (Length == 0 && WriteLength != DataRunLength * Vcb->NtfsInfo.BytesPerCluster)
1581 break;
1582
1583 // Go to next run in the list.
1584
1585 if (*DataRun == 0)
1586 {
1587 // that was the last run
1588 if (Length > 0)
1589 {
1590 // Failed sanity check.
1591 DPRINT1("Encountered EOF before expected!\n");
1593 goto Cleanup;
1594 }
1595
1596 break;
1597 }
1598
1599 // Advance to the next data run
1600 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1601 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1602 if (DataRunOffset != -1)
1603 {
1604 // Normal data run.
1605 DataRunStartLCN = LastLCN + DataRunOffset;
1606 LastLCN = DataRunStartLCN;
1607 }
1608 else
1609 {
1610 // Sparse data run.
1611 DataRunStartLCN = -1;
1612 }
1613 } // end while (Length > 0) [more data to write]
1614
1615 Context->CacheRun = DataRun;
1616 Context->CacheRunOffset = Offset + *RealLengthWritten;
1617 Context->CacheRunStartLCN = DataRunStartLCN;
1618 Context->CacheRunLength = DataRunLength;
1619 Context->CacheRunLastLCN = LastLCN;
1620 Context->CacheRunCurrentOffset = CurrentOffset;
1621
1622Cleanup:
1623 // TEMPTEMP
1624 if (Context->pRecord->IsNonResident)
1625 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
1626
1627 return Status;
1628}
ULONG WriteLength
Definition: CcPinRead_drv.c:40
NTSTATUS NtfsWriteDisk(IN PDEVICE_OBJECT DeviceObject, IN LONGLONG StartingOffset, IN ULONG Length, IN ULONG SectorSize, IN const PUCHAR Buffer)
Definition: blockdev.c:163

Referenced by AddNewMftEntry(), AllocateIndexNode(), FreeClusters(), IncreaseMftSize(), NtfsAddFilenameToDirectory(), NtfsAllocateClusters(), NtfsWriteFile(), SetResidentAttributeDataLength(), UpdateFileNameRecord(), UpdateFileRecord(), UpdateIndexEntryFileNameSize(), UpdateIndexNode(), and UpdateMftMirror().

Variable Documentation

◆ DriverEntry

DRIVER_INITIALIZE DriverEntry

Definition at line 1287 of file ntfs.h.

◆ NtfsFastIoCheckIfPossible

FAST_IO_CHECK_IF_POSSIBLE NtfsFastIoCheckIfPossible

Definition at line 914 of file ntfs.h.

Referenced by DriverEntry().

◆ NtfsFastIoRead

FAST_IO_READ NtfsFastIoRead

Definition at line 915 of file ntfs.h.

Referenced by DriverEntry().

◆ NtfsFastIoWrite

FAST_IO_WRITE NtfsFastIoWrite

Definition at line 916 of file ntfs.h.

Referenced by DriverEntry().

◆ NtfsFsdDispatch

DRIVER_DISPATCH NtfsFsdDispatch

Definition at line 892 of file ntfs.h.

Referenced by NtfsInitializeFunctionPointers().

◆ NtfsGlobalData