ReactOS  0.4.14-dev-114-gc8cbd56
mft.c File Reference
#include "ntfs.h"
#include <ntintsafe.h>
#include <debug.h>
Include dependency graph for mft.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

PNTFS_ATTR_CONTEXT PrepareAttributeContext (PNTFS_ATTR_RECORD AttrRecord)
 
VOID ReleaseAttributeContext (PNTFS_ATTR_CONTEXT Context)
 
FindAttribute

@implemented

Searches a file record for an attribute matching the given type and name.

Parameters
OffsetOptional pointer to a ULONG that will receive the offset of the found attribute from the beginning of the record. Can be set to NULL.
NTSTATUS FindAttribute (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER MftRecord, ULONG Type, PCWSTR Name, ULONG NameLength, PNTFS_ATTR_CONTEXT *AttrCtx, PULONG Offset)
 
ULONGLONG AttributeAllocatedLength (PNTFS_ATTR_RECORD AttrRecord)
 
ULONGLONG AttributeDataLength (PNTFS_ATTR_RECORD AttrRecord)
 
IncreaseMftSize

@implemented

Increases the size of the master file table on a volume, increasing the space available for file records.

Parameters
VcbPointer to the VCB (DEVICE_EXTENSION) of the target volume.
CanWaitBoolean indicating if the function is allowed to wait for exclusive access to the master file table. This will only be relevant if the MFT doesn't have any free file records and needs to be enlarged.
Returns
STATUS_SUCCESS on success. STATUS_INSUFFICIENT_RESOURCES if an allocation fails. STATUS_INVALID_PARAMETER if there was an error reading the Mft's bitmap. STATUS_CANT_WAIT if CanWait was FALSE and the function could not get immediate, exclusive access to the MFT.
Remarks
Increases the size of the Master File Table by 64 records. Bitmap entries for the new records are cleared, and the bitmap is also enlarged if needed. Mimicking Windows' behavior when enlarging the mft is still TODO. This function will wait for exlusive access to the volume fcb.
NTSTATUS IncreaseMftSize (PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
 
MoveAttributes

@implemented

Moves a block of attributes to a new location in the file Record. The attribute at FirstAttributeToMove and every attribute after that will be moved to MoveTo.

Parameters
DeviceExtPointer to the DEVICE_EXTENSION (VCB) of the target volume.
FirstAttributeToMovePointer to the first NTFS_ATTR_RECORD that needs to be moved. This pointer must reside within a file record.
FirstAttributeOffsetOffset of FirstAttributeToMove relative to the beginning of the file record.
MoveToULONG_PTR with the memory location that will be the new location of the first attribute being moved.
Returns
The new location of the final attribute (i.e. AttributeEnd marker).
PNTFS_ATTR_RECORD MoveAttributes (PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_RECORD FirstAttributeToMove, ULONG FirstAttributeOffset, ULONG_PTR MoveTo)
 
NTSTATUS InternalSetResidentAttributeLength (PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_CONTEXT AttrContext, PFILE_RECORD_HEADER FileRecord, ULONG AttrOffset, ULONG DataSize)
 
NTSTATUS SetAttributeDataLength (PFILE_OBJECT FileObject, PNTFS_FCB Fcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
 
SetFileRecordEnd

@implemented

This small function sets a new endpoint for the file record. It set's the final AttrEnd->Type to AttributeEnd and recalculates the bytes used by the file record.

Parameters
FileRecordPointer to the file record whose endpoint (length) will be set.
AttrEndPointer to section of memory that will receive the AttributeEnd marker. This must point to memory allocated for the FileRecord. Must be aligned to an 8-byte boundary (relative to FileRecord).
EndMarkerThis value will be written after AttributeEnd but isn't critical at all. When Windows resizes a file record, it preserves the final ULONG that previously ended the record, even though this value is (to my knowledge) never used. We emulate this behavior.
VOID SetFileRecordEnd (PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttrEnd, ULONG EndMarker)
 
SetNonResidentAttributeDataLength

@implemented

Called by SetAttributeDataLength() to set the size of a non-resident attribute. Doesn't update the file record.

Parameters
VcbPointer to a DEVICE_EXTENSION describing the target disk.
AttrContextPNTFS_ATTR_CONTEXT describing the location of the attribute whose size is being set.
AttrOffsetOffset, from the beginning of the record, of the attribute being sized.
FileRecordPointer to a file record containing the attribute to be resized. Must be a complete file record, not just the header.
DataSizePointer to a LARGE_INTEGER describing the new size of the attribute's data.
Returns
STATUS_SUCCESS on success; STATUS_INSUFFICIENT_RESOURCES if an allocation fails. STATUS_INVALID_PARAMETER if we can't find the last cluster in the data run.
Remarks
Called by SetAttributeDataLength() and IncreaseMftSize(). Use SetAttributeDataLength() unless you have a good reason to use this. Doesn't update the file record on disk. Doesn't inform the cache controller of changes with any associated files. Synchronization is the callers responsibility.
NTSTATUS SetNonResidentAttributeDataLength (PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
 
SetResidentAttributeDataLength

@implemented

Called by SetAttributeDataLength() to set the size of a non-resident attribute. Doesn't update the file record.

Parameters
VcbPointer to a DEVICE_EXTENSION describing the target disk.
AttrContextPNTFS_ATTR_CONTEXT describing the location of the attribute whose size is being set.
AttrOffsetOffset, from the beginning of the record, of the attribute being sized.
FileRecordPointer to a file record containing the attribute to be resized. Must be a complete file record, not just the header.
DataSizePointer to a LARGE_INTEGER describing the new size of the attribute's data.
Returns
STATUS_SUCCESS on success; STATUS_INSUFFICIENT_RESOURCES if an allocation fails. STATUS_INVALID_PARAMETER if AttrContext describes a non-resident attribute. STATUS_NOT_IMPLEMENTED if requested to decrease the size of an attribute that isn't the last attribute listed in the file record.
Remarks
Called by SetAttributeDataLength() and IncreaseMftSize(). Use SetAttributeDataLength() unless you have a good reason to use this. Doesn't update the file record on disk. Doesn't inform the cache controller of changes with any associated files. Synchronization is the callers responsibility.
NTSTATUS SetResidentAttributeDataLength (PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
 
ULONG ReadAttribute (PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
 
WriteAttribute

@implemented

Writes an NTFS attribute to the disk. It presently borrows a lot of code from ReadAttribute(), and it still needs more documentation / cleaning up.

Parameters
VcbVolume Control Block indicating which volume to write the attribute to
ContextPointer to an NTFS_ATTR_CONTEXT that has information about the attribute
OffsetOffset, in bytes, from the beginning of the attribute indicating where to start writing data
BufferThe data that's being written to the device
LengthHow much data will be written, in bytes
RealLengthWrittenPointer to a ULONG which will receive how much data was written, in bytes
FileRecordOptional pointer to a FILE_RECORD_HEADER that contains a copy of the file record being written to. Can be NULL, in which case the file record will be read from disk. If not-null, WriteAttribute() will skip reading from disk, and FileRecord will be updated with the newly-written attribute before the function returns.
Returns
STATUS_SUCCESS if successful, an error code otherwise. STATUS_NOT_IMPLEMENTED if writing to a sparse file.
Remarks
Note that in this context the word "attribute" isn't referring read-only, hidden, etc. - the file's data is actually stored in an attribute in NTFS parlance.
NTSTATUS WriteAttribute (PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, const PUCHAR Buffer, ULONG Length, PULONG RealLengthWritten, PFILE_RECORD_HEADER FileRecord)
 
NTSTATUS ReadFileRecord (PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
 
NTSTATUS UpdateFileNameRecord (PDEVICE_EXTENSION Vcb, ULONGLONG ParentMFTIndex, PUNICODE_STRING FileName, BOOLEAN DirSearch, ULONGLONG NewDataSize, ULONGLONG NewAllocationSize, BOOLEAN CaseSensitive)
 
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)
 
UpdateFileRecord

@implemented

Writes a file record to the master file table, at a given index.

Parameters
VcbPointer to the DEVICE_EXTENSION of the target drive being written to.
MftIndexTarget index in the master file table to store the file record.
FileRecordPointer to the complete file record which will be written to the master file table.
Returns
STATUS_SUCCESSFUL on success. An error passed from WriteAttribute() otherwise.
NTSTATUS UpdateFileRecord (PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
 
NTSTATUS FixupUpdateSequenceArray (PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
 
AddNewMftEntry

@implemented

Adds a file record to the master file table of a given device.

Parameters
FileRecordPointer to a complete file record which will be saved to disk.
DeviceExtPointer to the DEVICE_EXTENSION of the target drive.
DestinationIndexPointer to a ULONGLONG which will receive the MFT index where the file record was stored.
CanWaitBoolean indicating if the function is allowed to wait for exclusive access to the master file table. This will only be relevant if the MFT doesn't have any free file records and needs to be enlarged.
Returns
STATUS_SUCCESS on success. STATUS_OBJECT_NAME_NOT_FOUND if we can't find the MFT's $Bitmap or if we weren't able to read the attribute. STATUS_INSUFFICIENT_RESOURCES if we can't allocate enough memory for a copy of $Bitmap. STATUS_CANT_WAIT if CanWait was FALSE and the function could not get immediate, exclusive access to the MFT.
NTSTATUS AddNewMftEntry (PFILE_RECORD_HEADER FileRecord, PDEVICE_EXTENSION DeviceExt, PULONGLONG DestinationIndex, BOOLEAN CanWait)
 
NtfsAddFilenameToDirectory

@implemented

Adds a $FILE_NAME attribute to a given directory index.

Parameters
DeviceExtPoints to the target disk's DEVICE_EXTENSION.
DirectoryMftIndexMft index of the parent directory which will receive the file.
FileReferenceNumberFile reference of the file to be added to the directory. This is a combination of the Mft index and sequence number.
FilenameAttributePointer to the FILENAME_ATTRIBUTE of the file being added to the directory.
CaseSensitiveBoolean indicating if the function should operate in case-sensitive mode. This will be TRUE if an application created the file with the FILE_FLAG_POSIX_SEMANTICS flag.
Returns
STATUS_SUCCESS on success. STATUS_INSUFFICIENT_RESOURCES if an allocation fails. STATUS_NOT_IMPLEMENTED if target address isn't at the end of the given file record.
Remarks
WIP - Can only support a few files in a directory. One FILENAME_ATTRIBUTE is added to the directory's index for each link to that file. So, each file which contains one FILENAME_ATTRIBUTE for a long name and another for the 8.3 name, will get both attributes added to its parent directory.
NTSTATUS NtfsAddFilenameToDirectory (PDEVICE_EXTENSION DeviceExt, ULONGLONG DirectoryMftIndex, ULONGLONG FileReferenceNumber, PFILENAME_ATTRIBUTE FilenameAttribute, BOOLEAN CaseSensitive)
 
NTSTATUS AddFixupArray (PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
 
NTSTATUS ReadLCN (PDEVICE_EXTENSION Vcb, ULONGLONG lcn, ULONG count, PVOID buffer)
 
BOOLEAN CompareFileName (PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive)
 
UpdateMftMirror

@implemented

Backs-up the first ~4 master file table entries to the $MFTMirr file.

Parameters
VcbPointer to an NTFS_VCB for the volume whose Mft mirror is being updated.
Returns

STATUS_SUCCESS on success. STATUS_INSUFFICIENT_RESOURCES if an allocation failed. STATUS_UNSUCCESSFUL if we couldn't read the master file table.

Remarks
NTFS maintains up-to-date copies of the first several mft entries in the $MFTMirr file. Usually, the first 4 file records from the mft are stored. The exact number of entries is determined by the size of $MFTMirr's $DATA. If $MFTMirr is not up-to-date, chkdsk will reject every change it can find prior to when $MFTMirr was last updated. Therefore, it's recommended to call this function if the volume changes considerably. For instance, IncreaseMftSize() relies on this function to keep chkdsk from deleting the mft entries it creates. Note that under most instances, creating or deleting a file will not affect the first ~four mft entries, and so will not require updating the mft mirror.
NTSTATUS UpdateMftMirror (PNTFS_VCB Vcb)
 
NTSTATUS BrowseSubNodeIndexEntries (PNTFS_VCB Vcb, PFILE_RECORD_HEADER MftRecord, ULONG IndexBlockSize, PUNICODE_STRING FileName, PNTFS_ATTR_CONTEXT IndexAllocationContext, PRTL_BITMAP Bitmap, ULONGLONG VCN, PULONG StartEntry, PULONG CurrentEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
 
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)
 
NTSTATUS NtfsFindMftRecord (PDEVICE_EXTENSION Vcb, ULONGLONG MFTIndex, PUNICODE_STRING FileName, PULONG FirstEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
 
NTSTATUS NtfsLookupFileAt (PDEVICE_EXTENSION Vcb, PUNICODE_STRING PathName, BOOLEAN CaseSensitive, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex, ULONGLONG CurrentMFTIndex)
 
NTSTATUS NtfsLookupFile (PDEVICE_EXTENSION Vcb, PUNICODE_STRING PathName, BOOLEAN CaseSensitive, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex)
 
void NtfsDumpData (ULONG_PTR Buffer, ULONG Length)
 
NtfsDumpFileRecord

@implemented

Provides diagnostic information about a file record. Prints a hex dump of the entire record (based on the size reported by FileRecord->ByesInUse), then prints a dump of each attribute.

Parameters
VcbPointer to a DEVICE_EXTENSION describing the volume.
FileRecordPointer to the file record to be analyzed.
Remarks
FileRecord must be a complete file record at least FileRecord->BytesAllocated in size, and not just the header.
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)
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 35 of file mft.c.

Function Documentation

◆ 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 }
signed char * PCHAR
Definition: retypes.h:7
struct FIXUP_ARRAY * PFIXUP_ARRAY
_In_ struct _KBUGCHECK_REASON_CALLBACK_RECORD * Record
Definition: ketypes.h:256
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
USHORT USN
Definition: ntfs.h:557
void DPRINT(...)
Definition: polytest.cpp:61
#define Vcb
Definition: cdprocs.h:1425
unsigned char UCHAR
Definition: xmlstorage.h:181
unsigned short USHORT
Definition: pedump.c:61
unsigned int ULONG
Definition: retypes.h:1
USHORT Array[]
Definition: ntfs.h:558
return STATUS_SUCCESS
Definition: btrfs.c:2966

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

◆ 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);
2092  return STATUS_NOT_IMPLEMENTED;
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 }
signed char * PCHAR
Definition: retypes.h:7
NTSTATUS IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
Definition: mft.c:293
NTSYSAPI void WINAPI RtlInitializeBitMap(PRTL_BITMAP, PULONG, ULONG)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:225
ULONG MFTRecordNumber
Definition: ntfs.h:258
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
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
PNTFS_GLOBAL_DATA NtfsGlobalData
Definition: ntfs.c:41
uint32_t ULONG_PTR
Definition: typedefs.h:63
NTSTATUS AddNewMftEntry(PFILE_RECORD_HEADER FileRecord, PDEVICE_EXTENSION DeviceExt, PULONGLONG DestinationIndex, BOOLEAN CanWait)
Definition: mft.c:2022
long LONG
Definition: pedump.c:60
smooth NULL
Definition: ftsmooth.c:416
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
struct BitmapData BitmapData
#define TAG_NTFS
Definition: ntfs.h:12
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
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static ULONG BitmapBuffer[(XMS_BLOCKS+31)/32]
Definition: himem.c:86
unsigned char UCHAR
Definition: xmlstorage.h:181
static const WCHAR L[]
Definition: oid.c:1250
ULONG LowPart
Definition: typedefs.h:104
NTSYSAPI ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP, ULONG, ULONG)
Status
Definition: gdiplustypes.h:24
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
NTSTATUS UpdateFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1931
unsigned int * PULONG
Definition: retypes.h:1
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ALIGN_UP_BY(size, align)
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:2966
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
BOOLEAN EnableWriteSupport
Definition: ntfs.h:155
LONGLONG QuadPart
Definition: typedefs.h:112

Referenced by AddNewMftEntry(), 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 }
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:316
UCHAR IsNonResident
Definition: ntfs.h:124
struct NTFS_ATTR_RECORD::@165::@168 NonResident
#define ALIGN_UP_BY(size, align)
struct NTFS_ATTR_RECORD::@165::@167 Resident

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

◆ AttributeDataLength()

◆ BrowseIndexEntries()

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 at line 2984 of file mft.c.

2996 {
2997  NTSTATUS Status;
2998  PINDEX_ENTRY_ATTRIBUTE IndexEntry;
2999  PNTFS_ATTR_CONTEXT IndexAllocationContext;
3000  PNTFS_ATTR_CONTEXT BitmapContext;
3001  PCHAR *BitmapMem;
3002  ULONG *BitmapPtr;
3004 
3005  DPRINT("BrowseIndexEntries(%p, %p, %p, %lu, %p, %p, %wZ, %lu, %lu, %s, %s, %p)\n",
3006  Vcb,
3007  MftRecord,
3008  IndexRecord,
3009  IndexBlockSize,
3010  FirstEntry,
3011  LastEntry,
3012  FileName,
3013  *StartEntry,
3014  *CurrentEntry,
3015  DirSearch ? "TRUE" : "FALSE",
3016  CaseSensitive ? "TRUE" : "FALSE",
3017  OutMFTIndex);
3018 
3019  // Find the $I30 index allocation, if there is one
3020  Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationContext, NULL);
3021  if (NT_SUCCESS(Status))
3022  {
3023  ULONGLONG BitmapLength;
3024  // Find the bitmap attribute for the index
3025  Status = FindAttribute(Vcb, MftRecord, AttributeBitmap, L"$I30", 4, &BitmapContext, NULL);
3026  if (!NT_SUCCESS(Status))
3027  {
3028  DPRINT1("Potential file system corruption detected!\n");
3029  ReleaseAttributeContext(IndexAllocationContext);
3030  return Status;
3031  }
3032 
3033  // Get the length of the bitmap attribute
3034  BitmapLength = AttributeDataLength(BitmapContext->pRecord);
3035 
3036  // Allocate memory for the bitmap, including some padding; RtlInitializeBitmap() wants a pointer
3037  // that's ULONG-aligned, and it wants the size of the memory allocated for it to be a ULONG-multiple.
3038  BitmapMem = ExAllocatePoolWithTag(NonPagedPool, BitmapLength + sizeof(ULONG), TAG_NTFS);
3039  if (!BitmapMem)
3040  {
3041  DPRINT1("Error: failed to allocate bitmap!");
3042  ReleaseAttributeContext(BitmapContext);
3043  ReleaseAttributeContext(IndexAllocationContext);
3045  }
3046 
3047  RtlZeroMemory(BitmapMem, BitmapLength + sizeof(ULONG));
3048 
3049  // RtlInitializeBitmap() wants a pointer that's ULONG-aligned.
3050  BitmapPtr = (PULONG)ALIGN_UP_BY((ULONG_PTR)BitmapMem, sizeof(ULONG));
3051 
3052  // Read the existing bitmap data
3053  Status = ReadAttribute(Vcb, BitmapContext, 0, (PCHAR)BitmapPtr, BitmapLength);
3054  if (!NT_SUCCESS(Status))
3055  {
3056  DPRINT1("ERROR: Failed to read bitmap attribute!\n");
3057  ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3058  ReleaseAttributeContext(BitmapContext);
3059  ReleaseAttributeContext(IndexAllocationContext);
3060  return Status;
3061  }
3062 
3063  // Initialize bitmap
3064  RtlInitializeBitMap(&Bitmap, BitmapPtr, BitmapLength * 8);
3065  }
3066  else
3067  {
3068  // Couldn't find an index allocation
3069  IndexAllocationContext = NULL;
3070  }
3071 
3072 
3073  // Loop through all Index Entries of index, starting with FirstEntry
3074  IndexEntry = FirstEntry;
3075  while (IndexEntry <= LastEntry)
3076  {
3077  // Does IndexEntry have a sub-node?
3078  if (IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
3079  {
3080  if (!(IndexRecord->Header.Flags & INDEX_ROOT_LARGE) || !IndexAllocationContext)
3081  {
3082  DPRINT1("Filesystem corruption detected!\n");
3083  }
3084  else
3085  {
3087  MftRecord,
3088  IndexBlockSize,
3089  FileName,
3090  IndexAllocationContext,
3091  &Bitmap,
3092  GetIndexEntryVCN(IndexEntry),
3093  StartEntry,
3094  CurrentEntry,
3095  DirSearch,
3096  CaseSensitive,
3097  OutMFTIndex);
3098  if (NT_SUCCESS(Status))
3099  {
3100  ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3101  ReleaseAttributeContext(BitmapContext);
3102  ReleaseAttributeContext(IndexAllocationContext);
3103  return Status;
3104  }
3105  }
3106  }
3107 
3108  // Are we done?
3109  if (IndexEntry->Flags & NTFS_INDEX_ENTRY_END)
3110  break;
3111 
3112  // If we've found a file whose index is greater than or equal to StartEntry that matches the search criteria
3113  if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= NTFS_FILE_FIRST_USER_FILE &&
3114  *CurrentEntry >= *StartEntry &&
3115  IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
3116  CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
3117  {
3118  *StartEntry = *CurrentEntry;
3119  *OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
3120  if (IndexAllocationContext)
3121  {
3122  ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3123  ReleaseAttributeContext(BitmapContext);
3124  ReleaseAttributeContext(IndexAllocationContext);
3125  }
3126  return STATUS_SUCCESS;
3127  }
3128 
3129  // Advance to the next index entry
3130  (*CurrentEntry) += 1;
3131  ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
3132  IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
3133  }
3134 
3135  if (IndexAllocationContext)
3136  {
3137  ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3138  ReleaseAttributeContext(BitmapContext);
3139  ReleaseAttributeContext(IndexAllocationContext);
3140  }
3141 
3143 }
signed char * PCHAR
Definition: retypes.h:7
#define NTFS_MFT_MASK
Definition: ntfs.h:198
#define NTFS_FILE_NAME_DOS
Definition: ntfs.h:65
NTSYSAPI void WINAPI RtlInitializeBitMap(PRTL_BITMAP, PULONG, ULONG)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
BOOLEAN CompareFileName(PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive)
Definition: mft.c:2650
FILENAME_ATTRIBUTE FileName
Definition: ntfs.h:423
LONG NTSTATUS
Definition: precomp.h:26
USHORT Length
Definition: ntfs.h:419
struct INDEX_ENTRY_ATTRIBUTE::@750::@751 Directory
Definition: ntfs.h:404
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
#define NTFS_INDEX_ENTRY_END
Definition: ntfs.h:61
uint32_t ULONG_PTR
Definition: typedefs.h:63
union INDEX_ENTRY_ATTRIBUTE::@750 Data
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
ULONGLONG GetIndexEntryVCN(PINDEX_ENTRY_ATTRIBUTE IndexEntry)
Definition: btree.c:1641
#define NTFS_FILE_FIRST_USER_FILE
Definition: ntfs.h:196
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define Vcb
Definition: cdprocs.h:1425
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:394
#define TAG_NTFS
Definition: ntfs.h:12
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
USHORT Flags
Definition: ntfs.h:421
static const WCHAR L[]
Definition: oid.c:1250
#define INDEX_ROOT_LARGE
Definition: ntfs.h:209
#define NTFS_INDEX_ENTRY_NODE
Definition: ntfs.h:60
Status
Definition: gdiplustypes.h:24
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
unsigned int * PULONG
Definition: retypes.h:1
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ALIGN_UP_BY(size, align)
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:2966
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
struct INDEX_ENTRY_ATTRIBUTE * PINDEX_ENTRY_ATTRIBUTE
NTSTATUS BrowseSubNodeIndexEntries(PNTFS_VCB Vcb, PFILE_RECORD_HEADER MftRecord, ULONG IndexBlockSize, PUNICODE_STRING FileName, PNTFS_ATTR_CONTEXT IndexAllocationContext, PRTL_BITMAP Bitmap, ULONGLONG VCN, PULONG StartEntry, PULONG CurrentEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
Definition: mft.c:2839
UCHAR NameType
Definition: ntfs.h:374

Referenced by NtfsFindMftRecord().

◆ BrowseSubNodeIndexEntries()

NTSTATUS BrowseSubNodeIndexEntries ( PNTFS_VCB  Vcb,
PFILE_RECORD_HEADER  MftRecord,
ULONG  IndexBlockSize,
PUNICODE_STRING  FileName,
PNTFS_ATTR_CONTEXT  IndexAllocationContext,
PRTL_BITMAP  Bitmap,
ULONGLONG  VCN,
PULONG  StartEntry,
PULONG  CurrentEntry,
BOOLEAN  DirSearch,
BOOLEAN  CaseSensitive,
ULONGLONG OutMFTIndex 
)

Definition at line 2839 of file mft.c.

2851 {
2852  PINDEX_BUFFER IndexRecord;
2853  ULONGLONG Offset;
2854  ULONG BytesRead;
2855  PINDEX_ENTRY_ATTRIBUTE FirstEntry;
2856  PINDEX_ENTRY_ATTRIBUTE LastEntry;
2857  PINDEX_ENTRY_ATTRIBUTE IndexEntry;
2858  ULONG NodeNumber;
2859  NTSTATUS Status;
2860 
2861  DPRINT("BrowseSubNodeIndexEntries(%p, %p, %lu, %wZ, %p, %p, %I64d, %lu, %lu, %s, %s, %p)\n",
2862  Vcb,
2863  MftRecord,
2864  IndexBlockSize,
2865  FileName,
2866  IndexAllocationContext,
2867  Bitmap,
2868  VCN,
2869  *StartEntry,
2870  *CurrentEntry,
2871  "FALSE",
2872  DirSearch ? "TRUE" : "FALSE",
2873  CaseSensitive ? "TRUE" : "FALSE",
2874  OutMFTIndex);
2875 
2876  // Calculate node number as VCN / Clusters per index record
2877  NodeNumber = VCN / (Vcb->NtfsInfo.BytesPerIndexRecord / Vcb->NtfsInfo.BytesPerCluster);
2878 
2879  // Is the bit for this node clear in the bitmap?
2880  if (!RtlCheckBit(Bitmap, NodeNumber))
2881  {
2882  DPRINT1("File system corruption detected, node with VCN %I64u is marked as deleted.\n", VCN);
2883  return STATUS_DATA_ERROR;
2884  }
2885 
2886  // Allocate memory for the index record
2887  IndexRecord = ExAllocatePoolWithTag(NonPagedPool, IndexBlockSize, TAG_NTFS);
2888  if (!IndexRecord)
2889  {
2890  DPRINT1("Unable to allocate memory for index record!\n");
2892  }
2893 
2894  // Calculate offset of index record
2895  Offset = VCN * Vcb->NtfsInfo.BytesPerCluster;
2896 
2897  // Read the index record
2898  BytesRead = ReadAttribute(Vcb, IndexAllocationContext, Offset, (PCHAR)IndexRecord, IndexBlockSize);
2899  if (BytesRead != IndexBlockSize)
2900  {
2901  DPRINT1("Unable to read index record!\n");
2902  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2903  return STATUS_UNSUCCESSFUL;
2904  }
2905 
2906  // Assert that we're dealing with an index record here
2907  ASSERT(IndexRecord->Ntfs.Type == NRH_INDX_TYPE);
2908 
2909  // Apply the fixup array to the index record
2910  Status = FixupUpdateSequenceArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
2911  if (!NT_SUCCESS(Status))
2912  {
2913  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2914  DPRINT1("Failed to apply fixup array!\n");
2915  return Status;
2916  }
2917 
2918  ASSERT(IndexRecord->Header.AllocatedSize + FIELD_OFFSET(INDEX_BUFFER, Header) == IndexBlockSize);
2919  FirstEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexRecord->Header + IndexRecord->Header.FirstEntryOffset);
2920  LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexRecord->Header + IndexRecord->Header.TotalSizeOfEntries);
2921  ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexRecord + IndexBlockSize));
2922 
2923  // Loop through all Index Entries of index, starting with FirstEntry
2924  IndexEntry = FirstEntry;
2925  while (IndexEntry <= LastEntry)
2926  {
2927  // Does IndexEntry have a sub-node?
2928  if (IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
2929  {
2930  if (!(IndexRecord->Header.Flags & INDEX_NODE_LARGE) || !IndexAllocationContext)
2931  {
2932  DPRINT1("Filesystem corruption detected!\n");
2933  }
2934  else
2935  {
2937  MftRecord,
2938  IndexBlockSize,
2939  FileName,
2940  IndexAllocationContext,
2941  Bitmap,
2942  GetIndexEntryVCN(IndexEntry),
2943  StartEntry,
2944  CurrentEntry,
2945  DirSearch,
2946  CaseSensitive,
2947  OutMFTIndex);
2948  if (NT_SUCCESS(Status))
2949  {
2950  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2951  return Status;
2952  }
2953  }
2954  }
2955 
2956  // Are we done?
2957  if (IndexEntry->Flags & NTFS_INDEX_ENTRY_END)
2958  break;
2959 
2960  // If we've found a file whose index is greater than or equal to StartEntry that matches the search criteria
2961  if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= NTFS_FILE_FIRST_USER_FILE &&
2962  *CurrentEntry >= *StartEntry &&
2963  IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
2964  CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
2965  {
2966  *StartEntry = *CurrentEntry;
2967  *OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
2968  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2969  return STATUS_SUCCESS;
2970  }
2971 
2972  // Advance to the next index entry
2973  (*CurrentEntry) += 1;
2974  ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
2975  IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
2976  }
2977 
2978  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2979 
2981 }
signed char * PCHAR
Definition: retypes.h:7
#define NTFS_MFT_MASK
Definition: ntfs.h:198
#define NTFS_FILE_NAME_DOS
Definition: ntfs.h:65
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
BOOLEAN CompareFileName(PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive)
Definition: mft.c:2650
FILENAME_ATTRIBUTE FileName
Definition: ntfs.h:423
LONG NTSTATUS
Definition: precomp.h:26
USHORT Length
Definition: ntfs.h:419
struct INDEX_ENTRY_ATTRIBUTE::@750::@751 Directory
#define RtlCheckBit(BMH, BP)
Definition: rtlfuncs.h:3154
Definition: ntfs.h:404
#define NTFS_INDEX_ENTRY_END
Definition: ntfs.h:61
uint32_t ULONG_PTR
Definition: typedefs.h:63
_Out_ PUSHORT NodeNumber
Definition: iofuncs.h:2567
union INDEX_ENTRY_ATTRIBUTE::@750 Data
ULONG FirstEntryOffset
Definition: ntfs.h:380
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
Definition: Header.h:8
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:401
void DPRINT(...)
Definition: polytest.cpp:61
ULONGLONG GetIndexEntryVCN(PINDEX_ENTRY_ATTRIBUTE IndexEntry)
Definition: btree.c:1641
#define NTFS_FILE_FIRST_USER_FILE
Definition: ntfs.h:196
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define Vcb
Definition: cdprocs.h:1425
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151
#define TAG_NTFS
Definition: ntfs.h:12
NTSTATUS FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:1965
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
USHORT Flags
Definition: ntfs.h:421
ULONG TotalSizeOfEntries
Definition: ntfs.h:381
#define NTFS_INDEX_ENTRY_NODE
Definition: ntfs.h:60
#define NRH_INDX_TYPE
Definition: ntfs.h:243
Status
Definition: gdiplustypes.h:24
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
#define STATUS_DATA_ERROR
Definition: ntstatus.h:284
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
NTFS_RECORD_HEADER Ntfs
Definition: ntfs.h:399
#define INDEX_NODE_LARGE
Definition: ntfs.h:212
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:2966
struct INDEX_ENTRY_ATTRIBUTE * PINDEX_ENTRY_ATTRIBUTE
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
NTSTATUS BrowseSubNodeIndexEntries(PNTFS_VCB Vcb, PFILE_RECORD_HEADER MftRecord, ULONG IndexBlockSize, PUNICODE_STRING FileName, PNTFS_ATTR_CONTEXT IndexAllocationContext, PRTL_BITMAP Bitmap, ULONGLONG VCN, PULONG StartEntry, PULONG CurrentEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
Definition: mft.c:2839
UCHAR NameType
Definition: ntfs.h:374

Referenced by BrowseIndexEntries().

◆ 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 }
#define TRUE
Definition: types.h:120
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
FILENAME_ATTRIBUTE FileName
Definition: ntfs.h:423
USHORT MaximumLength
Definition: env_spec_w32.h:370
WCHAR Name[1]
Definition: ntfs.h:375
UCHAR NameLength
Definition: ntfs.h:373
#define NT_VERIFY(exp)
Definition: rtlfuncs.h:3289
BOOLEAN NTAPI FsRtlIsNameInExpression(IN PUNICODE_STRING Expression, IN PUNICODE_STRING Name, IN BOOLEAN IgnoreCase, IN PWCHAR UpcaseTable OPTIONAL)
Definition: name.c:514
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
struct _FileName FileName
Definition: fatprocs.h:884

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

◆ 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 {
139  BOOLEAN Found;
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 }
signed char * PCHAR
Definition: retypes.h:7
#define NTFS_MFT_MASK
Definition: ntfs.h:198
#define TRUE
Definition: types.h:120
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
Type
Definition: Type.h:6
USHORT NameOffset
Definition: ntfs.h:126
NTSTATUS FindFirstAttributeListItem(PFIND_ATTR_CONTXT Context, PNTFS_ATTRIBUTE_LIST_ITEM *Item)
Definition: attrib.c:1307
ULONG MFTRecordNumber
Definition: ntfs.h:258
LONG NTSTATUS
Definition: precomp.h:26
ULONG Type
Definition: ntfs.h:122
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
uint16_t * PWCHAR
Definition: typedefs.h:54
ULONGLONG MFTIndex
Definition: ntfs.h:310
PNTFS_ATTR_CONTEXT PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:41
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
return Found
Definition: dirsup.c:1270
NTSTATUS FindNextAttribute(PFIND_ATTR_CONTXT Context, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1431
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define Vcb
Definition: cdprocs.h:1425
VOID FindCloseAttribute(PFIND_ATTR_CONTXT Context)
Definition: attrib.c:1465
NTSTATUS FindNextAttributeListItem(PFIND_ATTR_CONTXT Context, PNTFS_ATTRIBUTE_LIST_ITEM *Item)
Definition: attrib.c:1321
Status
Definition: gdiplustypes.h:24
UCHAR NameLength
Definition: ntfs.h:125
NTSTATUS FindFirstAttribute(PFIND_ATTR_CONTXT Context, PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord, BOOLEAN OnlyResident, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1383
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
#define DPRINT1
Definition: precomp.h:8
struct tagContext Context
Definition: acpixf.h:1024
return STATUS_SUCCESS
Definition: btrfs.c:2966
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465

Referenced by AddNewMftEntry(), AllocateIndexNode(), BrowseIndexEntries(), CreateBTreeFromIndex(), FindAttribute(), tinyxml2::XMLElement::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().

◆ 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 }
signed char * PCHAR
Definition: retypes.h:7
_In_ struct _KBUGCHECK_REASON_CALLBACK_RECORD * Record
Definition: ketypes.h:256
void DPRINT(...)
Definition: polytest.cpp:61
#define Vcb
Definition: cdprocs.h:1425
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
unsigned short USHORT
Definition: pedump.c:61
#define DPRINT1
Definition: precomp.h:8
return STATUS_SUCCESS
Definition: btrfs.c:2966

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

◆ IncreaseMftSize()

NTSTATUS IncreaseMftSize ( PDEVICE_EXTENSION  Vcb,
BOOLEAN  CanWait 
)

Definition at line 293 of file mft.c.

294 {
295  PNTFS_ATTR_CONTEXT BitmapContext;
296  LARGE_INTEGER BitmapSize;
298  LONGLONG BitmapSizeDifference;
299  ULONG NewRecords = ATTR_RECORD_ALIGNMENT * 8; // Allocate one new record for every bit of every byte we'll be adding to the bitmap
300  ULONG DataSizeDifference = Vcb->NtfsInfo.BytesPerFileRecord * NewRecords;
301  ULONG BitmapOffset;
303  ULONGLONG BitmapBytes;
304  ULONGLONG NewBitmapSize;
305  ULONGLONG FirstNewMftIndex;
307  ULONG LengthWritten;
308  PFILE_RECORD_HEADER BlankFileRecord;
309  ULONG i;
311 
312  DPRINT1("IncreaseMftSize(%p, %s)\n", Vcb, CanWait ? "TRUE" : "FALSE");
313 
314  // We need exclusive access to the mft while we change its size
315  if (!ExAcquireResourceExclusiveLite(&(Vcb->DirResource), CanWait))
316  {
317  return STATUS_CANT_WAIT;
318  }
319 
320  // Create a blank file record that will be used later
321  BlankFileRecord = NtfsCreateEmptyFileRecord(Vcb);
322  if (!BlankFileRecord)
323  {
324  DPRINT1("Error: Unable to create empty file record!\n");
326  }
327 
328  // Clear the flags (file record is not in use)
329  BlankFileRecord->Flags = 0;
330 
331  // Find the bitmap attribute of master file table
332  Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
333  if (!NT_SUCCESS(Status))
334  {
335  DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
336  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
337  ExReleaseResourceLite(&(Vcb->DirResource));
338  return Status;
339  }
340 
341  // Get size of Bitmap Attribute
342  BitmapSize.QuadPart = AttributeDataLength(BitmapContext->pRecord);
343 
344  // Calculate the new mft size
345  DataSize.QuadPart = AttributeDataLength(Vcb->MFTContext->pRecord) + DataSizeDifference;
346 
347  // Find the index of the first Mft entry that will be created
348  FirstNewMftIndex = AttributeDataLength(Vcb->MFTContext->pRecord) / Vcb->NtfsInfo.BytesPerFileRecord;
349 
350  // Determine how many bytes will make up the bitmap
351  BitmapBytes = DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord / 8;
352  if ((DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord) % 8 != 0)
353  BitmapBytes++;
354 
355  // Windows will always keep the number of bytes in a bitmap as a multiple of 8, so no bytes are wasted on slack
356  BitmapBytes = ALIGN_UP_BY(BitmapBytes, ATTR_RECORD_ALIGNMENT);
357 
358  // Determine how much we need to adjust the bitmap size (it's possible we don't)
359  BitmapSizeDifference = BitmapBytes - BitmapSize.QuadPart;
360  NewBitmapSize = max(BitmapSize.QuadPart + BitmapSizeDifference, BitmapSize.QuadPart);
361 
362  // Allocate memory for the bitmap
364  if (!BitmapBuffer)
365  {
366  DPRINT1("ERROR: Unable to allocate memory for bitmap attribute!\n");
367  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
368  ExReleaseResourceLite(&(Vcb->DirResource));
369  ReleaseAttributeContext(BitmapContext);
371  }
372 
373  // Zero the bytes we'll be adding
374  RtlZeroMemory(BitmapBuffer, NewBitmapSize);
375 
376  // Read the bitmap attribute
378  BitmapContext,
379  0,
381  BitmapSize.LowPart);
382  if (BytesRead != BitmapSize.LowPart)
383  {
384  DPRINT1("ERROR: Bytes read != Bitmap size!\n");
385  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
386  ExReleaseResourceLite(&(Vcb->DirResource));
388  ReleaseAttributeContext(BitmapContext);
390  }
391 
392  // Increase the mft size
393  Status = SetNonResidentAttributeDataLength(Vcb, Vcb->MFTContext, Vcb->MftDataOffset, Vcb->MasterFileTable, &DataSize);
394  if (!NT_SUCCESS(Status))
395  {
396  DPRINT1("ERROR: Failed to set size of $MFT data attribute!\n");
397  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
398  ExReleaseResourceLite(&(Vcb->DirResource));
400  ReleaseAttributeContext(BitmapContext);
401  return Status;
402  }
403 
404  // We'll need to find the bitmap again, because its offset will have changed after resizing the data attribute
405  ReleaseAttributeContext(BitmapContext);
406  Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, &BitmapOffset);
407  if (!NT_SUCCESS(Status))
408  {
409  DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
410  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
411  ExReleaseResourceLite(&(Vcb->DirResource));
412  return Status;
413  }
414 
415  // If the bitmap grew
416  if (BitmapSizeDifference > 0)
417  {
418  // Set the new bitmap size
419  BitmapSize.QuadPart = NewBitmapSize;
420  if (BitmapContext->pRecord->IsNonResident)
421  Status = SetNonResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize);
422  else
423  Status = SetResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize);
424 
425  if (!NT_SUCCESS(Status))
426  {
427  DPRINT1("ERROR: Failed to set size of bitmap attribute!\n");
428  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
429  ExReleaseResourceLite(&(Vcb->DirResource));
431  ReleaseAttributeContext(BitmapContext);
432  return Status;
433  }
434  }
435 
436  NtfsDumpFileAttributes(Vcb, Vcb->MasterFileTable);
437 
438  // Update the file record with the new attribute sizes
439  Status = UpdateFileRecord(Vcb, Vcb->VolumeFcb->MFTIndex, Vcb->MasterFileTable);
440  if (!NT_SUCCESS(Status))
441  {
442  DPRINT1("ERROR: Failed to update $MFT file record!\n");
443  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
444  ExReleaseResourceLite(&(Vcb->DirResource));
446  ReleaseAttributeContext(BitmapContext);
447  return Status;
448  }
449 
450  // Write out the new bitmap
451  Status = WriteAttribute(Vcb, BitmapContext, 0, BitmapBuffer, NewBitmapSize, &LengthWritten, Vcb->MasterFileTable);
452  if (!NT_SUCCESS(Status))
453  {
454  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
455  ExReleaseResourceLite(&(Vcb->DirResource));
457  ReleaseAttributeContext(BitmapContext);
458  DPRINT1("ERROR: Couldn't write to bitmap attribute of $MFT!\n");
459  return Status;
460  }
461 
462  // Create blank records for the new file record entries.
463  for (i = 0; i < NewRecords; i++)
464  {
465  Status = UpdateFileRecord(Vcb, FirstNewMftIndex + i, BlankFileRecord);
466  if (!NT_SUCCESS(Status))
467  {
468  DPRINT1("ERROR: Failed to write blank file record!\n");
469  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
470  ExReleaseResourceLite(&(Vcb->DirResource));
472  ReleaseAttributeContext(BitmapContext);
473  return Status;
474  }
475  }
476 
477  // Update the mft mirror
479 
480  // Cleanup
481  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
482  ExReleaseResourceLite(&(Vcb->DirResource));
484  ReleaseAttributeContext(BitmapContext);
485 
486  return Status;
487 }
signed char * PCHAR
Definition: retypes.h:7
#define max(a, b)
Definition: svc.c:63
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
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
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
NTSTATUS SetResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:891
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
VOID NtfsDumpFileAttributes(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
Definition: attrib.c:1790
smooth NULL
Definition: ftsmooth.c:416
int64_t LONGLONG
Definition: typedefs.h:66
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:316
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define Vcb
Definition: cdprocs.h:1425
NTSTATUS SetNonResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:756
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
#define TAG_NTFS
Definition: ntfs.h:12
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
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static ULONG BitmapBuffer[(XMS_BLOCKS+31)/32]
Definition: himem.c:86
static const WCHAR L[]
Definition: oid.c:1250
ULONG LowPart
Definition: typedefs.h:104
Status
Definition: gdiplustypes.h:24
PFILE_RECORD_HEADER NtfsCreateEmptyFileRecord(PDEVICE_EXTENSION DeviceExt)
Definition: create.c:818
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
NTSTATUS UpdateFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1931
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
USHORT Flags
Definition: ntfs.h:252
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ALIGN_UP_BY(size, align)
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
LONGLONG QuadPart
Definition: typedefs.h:112
NTSTATUS UpdateMftMirror(PNTFS_VCB Vcb)
Definition: mft.c:2714
#define STATUS_CANT_WAIT
Definition: ntstatus.h:438

Referenced by AddNewMftEntry().

◆ 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
575  AttrContext->pRecord = ExAllocatePoolWithTag(NonPagedPool, Destination->Length, TAG_NTFS);
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 }
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
struct NTFS_ATTR_RECORD * PNTFS_ATTR_RECORD
#define FILE_RECORD_END
Definition: ntfs.h:182
ULONG Type
Definition: ntfs.h:122
uint32_t ULONG_PTR
Definition: typedefs.h:63
PNTFS_ATTR_RECORD MoveAttributes(PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_RECORD FirstAttributeToMove, ULONG FirstAttributeOffset, ULONG_PTR MoveTo)
Definition: mft.c:512
VOID SetFileRecordEnd(PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttrEnd, ULONG EndMarker)
Definition: mft.c:706
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:316
_In_ PUNICODE_STRING _Inout_ PUNICODE_STRING Destination
Definition: rtlfuncs.h:2891
#define TAG_NTFS
Definition: ntfs.h:12
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ALIGN_UP_BY(size, align)
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:2966
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751

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 }
signed char * PCHAR
Definition: retypes.h:7
struct NTFS_ATTR_RECORD * PNTFS_ATTR_RECORD
ULONG Type
Definition: ntfs.h:122
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint32_t ULONG_PTR
Definition: typedefs.h:63
ULONG Length
Definition: ntfs.h:123
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:316
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
unsigned int ULONG
Definition: retypes.h:1

Referenced by AddRun(), and InternalSetResidentAttributeLength().

◆ 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 }
signed char * PCHAR
Definition: retypes.h:7
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
struct NTFS_ATTR_RECORD * PNTFS_ATTR_RECORD
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
ULONG BytesInUse
Definition: ntfs.h:253
ULONG Type
Definition: ntfs.h:122
NTSTATUS DemoteBTreeRoot(PB_TREE Tree)
Definition: btree.c:1089
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
PB_TREE_FILENAME_NODE RootNode
Definition: ntfs.h:451
NTSTATUS CreateBTreeFromIndex(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecordWithIndex, PNTFS_ATTR_CONTEXT IndexRootContext, PINDEX_ROOT_ATTRIBUTE IndexRoot, PB_TREE *NewTree)
Definition: btree.c:682
uint32_t ULONG_PTR
Definition: typedefs.h:63
Definition: Header.h:8
ULONG Length
Definition: ntfs.h:123
smooth NULL
Definition: ftsmooth.c:416
ULONG SizeOfEntry
Definition: ntfs.h:391
NTSTATUS InternalSetResidentAttributeLength(PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_CONTEXT AttrContext, PFILE_RECORD_HEADER FileRecord, ULONG AttrOffset, ULONG DataSize)
Definition: mft.c:542
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:316
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:394
#define TAG_NTFS
Definition: ntfs.h:12
VOID DumpBTree(PB_TREE Tree)
Definition: btree.c:1622
ULONG GetSizeOfIndexEntries(PB_TREE_FILENAME_NODE Node)
Definition: btree.c:855
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
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
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
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
static const WCHAR L[]
Definition: oid.c:1250
NTSTATUS UpdateIndexAllocation(PDEVICE_EXTENSION DeviceExt, PB_TREE Tree, ULONG IndexBufferSize, PFILE_RECORD_HEADER FileRecord)
Definition: btree.c:1182
ULONG LowPart
Definition: typedefs.h:104
Status
Definition: gdiplustypes.h:24
VOID DestroyBTree(PB_TREE Tree)
Definition: btree.c:1542
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
NTSTATUS UpdateFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1931
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
Definition: ntfs.h:449
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
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
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:2966
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
LONGLONG QuadPart
Definition: typedefs.h:112
#define NT_ASSERT
Definition: rtlfuncs.h:3312

Referenced by NtfsCreateDirectory(), and NtfsCreateFileRecord().

◆ 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 }
#define DbgPrint
Definition: loader.c:25
unsigned char * PUCHAR
Definition: retypes.h:3
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
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
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
unsigned int ULONG
Definition: retypes.h:1

◆ 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 }
#define DbgPrint
Definition: loader.c:25
unsigned char * PUCHAR
Definition: retypes.h:3
ULONG BytesInUse
Definition: ntfs.h:253
uint32_t ULONG_PTR
Definition: typedefs.h:63
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
VOID NtfsDumpFileAttributes(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
Definition: attrib.c:1790
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
#define Vcb
Definition: cdprocs.h:1425
unsigned int ULONG
Definition: retypes.h:1

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

◆ 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 {
3363  NTSTATUS Status;
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 }
#define TRUE
Definition: types.h:120
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
LONG NTSTATUS
Definition: precomp.h:26
NTSTATUS NtfsFindMftRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MFTIndex, PUNICODE_STRING FileName, PULONG FirstEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
Definition: mft.c:3146
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define Vcb
Definition: cdprocs.h:1425
Status
Definition: gdiplustypes.h:24
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
return STATUS_SUCCESS
Definition: btrfs.c:2966

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;
3159  NTSTATUS Status;
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 }
signed char * PCHAR
Definition: retypes.h:7
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
LONG NTSTATUS
Definition: precomp.h:26
Definition: ntfs.h:404
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
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
ULONG FirstEntryOffset
Definition: ntfs.h:380
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
ULONG SizeOfEntry
Definition: ntfs.h:391
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define Vcb
Definition: cdprocs.h:1425
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:394
#define TAG_NTFS
Definition: ntfs.h:12
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static const WCHAR L[]
Definition: oid.c:1250
ULONG TotalSizeOfEntries
Definition: ntfs.h:381
Status
Definition: gdiplustypes.h:24
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
#define NRH_FILE_TYPE
Definition: ntfs.h:242
NTFS_RECORD_HEADER Ntfs
Definition: ntfs.h:248
unsigned int ULONG
Definition: retypes.h:1
struct INDEX_ROOT_ATTRIBUTE * PINDEX_ROOT_ATTRIBUTE
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
struct INDEX_ENTRY_ATTRIBUTE * PINDEX_ENTRY_ATTRIBUTE

Referenced by NtfsFindFileAt(), and NtfsLookupFileAt().

◆ 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
#define Vcb
Definition: cdprocs.h:1425
#define NTFS_FILE_ROOT
Definition: ntfs.h:28

◆ 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;
3237  NTSTATUS Status;
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 }
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
LONG NTSTATUS
Definition: precomp.h:26
NTSTATUS NtfsFindMftRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MFTIndex, PUNICODE_STRING FileName, PULONG FirstEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
Definition: mft.c:3146
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID NTAPI FsRtlDissectName(IN UNICODE_STRING Name, OUT PUNICODE_STRING FirstPart, OUT PUNICODE_STRING RemainingPart)
Definition: name.c:398
#define Vcb
Definition: cdprocs.h:1425
Status
Definition: gdiplustypes.h:24
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
unsigned int ULONG
Definition: retypes.h:1
return STATUS_SUCCESS
Definition: btrfs.c:2966

Referenced by NtfsDirFindFile(), and NtfsLookupFile().

◆ 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
53  Context->pRecord = ExAllocatePoolWithTag(NonPagedPool, AttrRecord->Length, TAG_NTFS);
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 }
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
NPAGED_LOOKASIDE_LIST AttrCtxtLookasideList
Definition: ntfs.h:154
unsigned char * PUCHAR
Definition: retypes.h:3
PUCHAR DecodeRun(PUCHAR DataRun, LONGLONG *DataRunOffset, ULONGLONG *DataRunLength)
Definition: attrib.c:966
PNTFS_GLOBAL_DATA NtfsGlobalData
Definition: ntfs.c:41
uint32_t ULONG_PTR
Definition: typedefs.h:63
NTSTATUS ConvertDataRunsToLargeMCB(PUCHAR DataRun, PLARGE_MCB DataRunsMCB, PULONGLONG pNextVBN)
Definition: attrib.c:825
ULONG Length
Definition: ntfs.h:123
smooth NULL
Definition: ftsmooth.c:416
int64_t LONGLONG
Definition: typedefs.h:66
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define TAG_NTFS
Definition: ntfs.h:12
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
UCHAR IsNonResident
Definition: ntfs.h:124
#define DPRINT1
Definition: precomp.h:8
struct tagContext Context
Definition: acpixf.h:1024
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099

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;
1077  ULONG ReadLength;
1078  ULONG AlreadyRead;
1079  NTSTATUS Status;
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  {
1179  RtlZeroMemory(Buffer, ReadLength);
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)
1214  RtlZeroMemory(Buffer, ReadLength);
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 }
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
PUCHAR DecodeRun(PUCHAR DataRun, LONGLONG *DataRunOffset, ULONGLONG *DataRunLength)
Definition: attrib.c:966
uint32_t ULONG_PTR
Definition: typedefs.h:63
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
smooth NULL
Definition: ftsmooth.c:416
Definition: bufpool.h:45
int64_t LONGLONG
Definition: typedefs.h:66
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define Vcb
Definition: cdprocs.h:1425
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define TAG_NTFS
Definition: ntfs.h:12
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
Status
Definition: gdiplustypes.h:24
NTSTATUS ConvertLargeMCBToDataRuns(PLARGE_MCB DataRunsMCB, PUCHAR RunBuffer, ULONG MaxBufferSize, PULONG UsedBufferSize)
Definition: attrib.c:896
#define min(a, b)
Definition: monoChain.cc:55
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:2966
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

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 }
signed char * PCHAR
Definition: retypes.h:7
void DPRINT(...)
Definition: polytest.cpp:61
GLuint index
Definition: glext.h:6031
uint64_t ULONGLONG
Definition: typedefs.h:65
#define Vcb
Definition: cdprocs.h:1425
NTSTATUS FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:1965
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
#define DPRINT1
Definition: precomp.h:8
#define STATUS_PARTIAL_COPY
Definition: ntstatus.h:181
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
Definition: fci.c:126

Referenced by FindAttribute(), FreeClusters(), GetNtfsFileRecord(), GetVolumeBitmap(), NtfsAddFilenameToDirectory(), NtfsAllocateClusters(), NtfsCreateFile(), NtfsFindFileAt(), NtfsFindMftRecord(), NtfsGetFreeClusters(), NtfsGetSteamInformation(), 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
struct _LARGE_INTEGER::@2205 u
#define Vcb
Definition: cdprocs.h:1425
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
LONGLONG QuadPart
Definition: typedefs.h:112

◆ ReleaseAttributeContext()

VOID ReleaseAttributeContext ( PNTFS_ATTR_CONTEXT  Context)

Definition at line 104 of file mft.c.

105 {
106  if (Context->pRecord)
107  {
108  if (Context->pRecord->IsNonResident)
109  {
110  FsRtlUninitializeLargeMcb(&Context->DataRunsMCB);
111  }
112 
114  }
115 
116  ExFreeToNPagedLookasideList(&NtfsGlobalData->AttrCtxtLookasideList, Context);
117 }
NPAGED_LOOKASIDE_LIST AttrCtxtLookasideList
Definition: ntfs.h:154
PNTFS_GLOBAL_DATA NtfsGlobalData
Definition: ntfs.c:41
#define TAG_NTFS
Definition: ntfs.h:12
VOID NTAPI FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:1053
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099

Referenced by AddNewMftEntry(), AllocateIndexNode(), BrowseIndexEntries(), CreateBTreeFromIndex(), FreeClusters(), GetVolumeBitmap(), IncreaseMftSize(), InternalReadNonResidentAttributes(), NtfsAddFilenameToDirectory(), NtfsAllocateClusters(), NtfsCreateFile(), NtfsDirFindFile(), NtfsFindMftRecord(), NtfsGetFileSize(), NtfsGetFreeClusters(), NtfsGetVolumeData(), NtfsReadFCBAttribute(), NtfsReadFile(), NtfsSetEndOfFile(), NtfsWriteFile(), UpdateFileNameRecord(), UpdateIndexAllocation(), UpdateIndexEntryFileNameSize(), UpdateMftMirror(), and WriteAttribute().

◆ 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",
625  FileObject,
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 }
BOOLEAN NTAPI MmCanFileBeTruncated(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN PLARGE_INTEGER NewFileSize)
Definition: section.c:4724
LONG NTSTATUS
Definition: precomp.h:26
ULONGLONG MFTIndex
Definition: ntfs.h:535
NTSTATUS SetResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:891
#define STATUS_USER_MAPPED_FILE
Definition: ntstatus.h:697
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:593
FSRTL_COMMON_FCB_HEADER RFCB
Definition: ntfs.h:513
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
NTSTATUS SetNonResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:756
LARGE_INTEGER AllocationSize
Definition: env_spec_w32.h:755
Status
Definition: gdiplustypes.h:24
VOID NTAPI CcSetFileSizes(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes)
Definition: fssup.c:354
NTSTATUS UpdateFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1931
#define DPRINT1
Definition: precomp.h:8
PVCB Vcb
Definition: cdstruc.h:939
_In_ PFCB Fcb
Definition: cdprocs.h:151
LARGE_INTEGER ValidDataLength
Definition: env_spec_w32.h:757
return STATUS_SUCCESS
Definition: btrfs.c:2966
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751
LONGLONG QuadPart
Definition: typedefs.h:112

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 }
ULONG BytesInUse
Definition: ntfs.h:253
ULONG Type
Definition: ntfs.h:122
uint32_t ULONG_PTR
Definition: typedefs.h:63
ULONG Length
Definition: ntfs.h:123
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:316
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
unsigned int ULONG
Definition: retypes.h:1
#define ULONG_PTR
Definition: config.h:101

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 }
#define ROUND_UP(n, align)
Definition: eventvwr.h:31
struct NTFS_ATTR_RECORD * PNTFS_ATTR_RECORD
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
NTSTATUS FreeClusters(PNTFS_VCB Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, ULONG ClustersToFree)
Definition: attrib.c:1057
LONG NTSTATUS
Definition: precomp.h:26
uint32_t ULONG_PTR
Definition: typedefs.h:63
__GNU_EXTENSION typedef __int64 * PLONGLONG
Definition: ntbasedef.h:389
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
int64_t LONGLONG
Definition: typedefs.h:66
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define Vcb
Definition: cdprocs.h:1425
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
ULONG LowPart
Definition: typedefs.h:104
NTSTATUS AddRun(PNTFS_VCB Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, ULONGLONG NextAssignedCluster, ULONG RunLength)
Definition: attrib.c:599
Status
Definition: gdiplustypes.h:24
IN PFCB IN PFILE_OBJECT FileObject IN ULONG AllocationSize
Definition: fatprocs.h:310
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:564
struct NTFS_ATTR_RECORD::@165::@168 NonResident
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
return STATUS_SUCCESS
Definition: btrfs.c:2966
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751
NTSTATUS NtfsAllocateClusters(PDEVICE_EXTENSION DeviceExt, ULONG FirstDesiredCluster, ULONG DesiredClusters, PULONG FirstAssignedCluster, PULONG AssignedClusters)
Definition: volinfo.c:105
LONGLONG QuadPart
Definition: typedefs.h:112

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
998  _SEH2_TRY
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 }
signed char * PCHAR
Definition: retypes.h:7
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
struct NTFS_ATTR_RECORD * PNTFS_ATTR_RECORD
#define FILE_RECORD_END
Definition: ntfs.h:182
LONG NTSTATUS
Definition: precomp.h:26
ULONG Type
Definition: ntfs.h:122
_SEH2_TRY
Definition: create.c:4250
uint32_t ULONG_PTR
Definition: typedefs.h:63
ULONG Length
Definition: ntfs.h:123
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
VOID NTAPI FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb, IN POOL_TYPE PoolType)
Definition: largemcb.c:450
smooth NULL
Definition: ftsmooth.c:416
VOID SetFileRecordEnd(PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttrEnd, ULONG EndMarker)
Definition: mft.c:706
NTSTATUS InternalSetResidentAttributeLength(PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_CONTEXT AttrContext, PFILE_RECORD_HEADER FileRecord, ULONG AttrOffset, ULONG DataSize)
Definition: mft.c:542
#define _SEH2_YIELD(STMT_)
Definition: pseh2_64.h:8
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:316
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define Vcb
Definition: cdprocs.h:1425
_In_ PUNICODE_STRING _Inout_ PUNICODE_STRING Destination
Definition: rtlfuncs.h:2891
NTSTATUS SetNonResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:756
#define TAG_NTFS
Definition: ntfs.h:12
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
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
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
UCHAR IsNonResident
Definition: ntfs.h:124
ULONG ValueLength
Definition: ntfs.h:134
Status
Definition: gdiplustypes.h:24
_SEH2_END
Definition: create.c:4424
struct NTFS_ATTR_RECORD::@165::@168 NonResident
NTSTATUS UpdateFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1931
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ALIGN_UP_BY(size, align)
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
return STATUS_SUCCESS
Definition: btrfs.c:2966
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751
LONGLONG QuadPart
Definition: typedefs.h:112

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

◆ 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;
1673  NTSTATUS Status;
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 }
signed char * PCHAR
Definition: retypes.h:7
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
Definition: ntfs.h:404
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 FirstEntryOffset
Definition: ntfs.h:380
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
ULONG SizeOfEntry
Definition: ntfs.h:391
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
#define Vcb
Definition: cdprocs.h:1425
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:394
#define TAG_NTFS
Definition: ntfs.h:12
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
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
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static const WCHAR L[]
Definition: oid.c:1250
ULONG TotalSizeOfEntries
Definition: ntfs.h:381
Status
Definition: gdiplustypes.h:24
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
#define DPRINT1
Definition: precomp.h:8
#define NRH_FILE_TYPE
Definition: ntfs.h:242
NTFS_RECORD_HEADER Ntfs
Definition: ntfs.h:248
unsigned int ULONG
Definition: retypes.h:1
struct INDEX_ROOT_ATTRIBUTE * PINDEX_ROOT_ATTRIBUTE
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
struct INDEX_ENTRY_ATTRIBUTE * PINDEX_ENTRY_ATTRIBUTE
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_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesWritten
Definition: fltkernel.h:1293
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
void DPRINT(...)
Definition: polytest.cpp:61
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define Vcb
Definition: cdprocs.h:1425
NTSTATUS FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:1965
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
Status
Definition: gdiplustypes.h:24
#define DPRINT1
Definition: precomp.h:8
NTFS_RECORD_HEADER Ntfs
Definition: ntfs.h:248
unsigned int ULONG
Definition: retypes.h:1
return STATUS_SUCCESS
Definition: btrfs.c:2966

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

◆ 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 {
1784  NTSTATUS Status;
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 }
signed char * PCHAR
Definition: retypes.h:7
#define NTFS_MFT_MASK
Definition: ntfs.h:198
#define NTFS_FILE_NAME_DOS
Definition: ntfs.h:65
ULONGLONG AllocatedSize
Definition: ntfs.h:361
NTSTATUS AddFixupArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:2603
BOOLEAN CompareFileName(PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive)
Definition: mft.c:2650
FILENAME_ATTRIBUTE FileName
Definition: ntfs.h:423
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
USHORT Length
Definition: ntfs.h:419
struct INDEX_ENTRY_ATTRIBUTE::@750::@751 Directory
Definition: ntfs.h:404
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
#define NTFS_INDEX_ENTRY_END
Definition: ntfs.h:61
uint32_t ULONG_PTR
Definition: typedefs.h:63
union INDEX_ENTRY_ATTRIBUTE::@750 Data
ULONG FirstEntryOffset
Definition: ntfs.h:380
Definition: Header.h:8
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:401
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
ULONGLONG DataSize
Definition: ntfs.h:362
#define NTFS_FILE_FIRST_USER_FILE
Definition: ntfs.h:196
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
uint64_t ULONGLONG
Definition: typedefs.h:65
#define Vcb
Definition: cdprocs.h:1425
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151
NTSTATUS FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:1965
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
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
USHORT Flags
Definition: ntfs.h:421
static const WCHAR L[]
Definition: oid.c:1250
ULONG TotalSizeOfEntries
Definition: ntfs.h:381
#define NTFS_INDEX_ENTRY_NODE
Definition: ntfs.h:60
#define NRH_INDX_TYPE
Definition: ntfs.h:243
Status
Definition: gdiplustypes.h:24
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
struct INDEX_BUFFER * PINDEX_BUFFER
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
NTFS_RECORD_HEADER Ntfs
Definition: ntfs.h:399
return STATUS_SUCCESS
Definition: btrfs.c:2966
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
struct INDEX_ENTRY_ATTRIBUTE * PINDEX_ENTRY_ATTRIBUTE
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
UCHAR NameType
Definition: ntfs.h:374

Referenced by UpdateFileNameRecord(), and UpdateIndexEntryFileNameSize().

◆ 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;
2721  NTSTATUS Status;
2722  ULONG BytesRead;
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 }
signed char * PCHAR
Definition: retypes.h:7
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
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
smooth NULL
Definition: ftsmooth.c:416
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define Vcb
Definition: cdprocs.h:1425
#define TAG_NTFS
Definition: ntfs.h:12
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
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
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static const WCHAR L[]
Definition: oid.c:1250
Status
Definition: gdiplustypes.h:24
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
#define DPRINT1
Definition: precomp.h:8
#define NTFS_FILE_MFTMIRR
Definition: ntfs.h:24
unsigned int ULONG
Definition: retypes.h:1
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
_Must_inspect_result_ _Out_writes_to_ DataLength PHIDP_DATA _Inout_ PULONG DataLength
Definition: hidpi.h:333
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
#define ULONG_MAX
Definition: limits.h:44

Referenced by IncreaseMftSize().

◆ WriteAttribute()

NTSTATUS WriteAttribute ( PDEVICE_EXTENSION  Vcb,
PNTFS_ATTR_CONTEXT  Context,
ULONGLONG  Offset,
const PUCHAR  Buffer,
ULONG  Length,
PULONG  RealLengthWritten,
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;
1329  ULONG WriteLength;
1330  NTSTATUS Status;
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");
1356  return STATUS_INVALID_PARAMETER;
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);
1402  return STATUS_INVALID_PARAMETER;
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(