ReactOS  0.4.13-dev-73-gcfe54aa
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 2547 of file mft.c.

2549 {
2550  USHORT *pShortToFixUp;
2551  ULONG ArrayEntryCount = Record->UsaCount - 1;
2552  ULONG Offset = Vcb->NtfsInfo.BytesPerSector - 2;
2553  ULONG i;
2554 
2555  PFIXUP_ARRAY fixupArray = (PFIXUP_ARRAY)((UCHAR*)Record + Record->UsaOffset);
2556 
2557  DPRINT("AddFixupArray(%p, %p)\n fixupArray->USN: %u, ArrayEntryCount: %u\n", Vcb, Record, fixupArray->USN, ArrayEntryCount);
2558 
2559  fixupArray->USN++;
2560 
2561  for (i = 0; i < ArrayEntryCount; i++)
2562  {
2563  DPRINT("USN: %u\tOffset: %u\n", fixupArray->USN, Offset);
2564 
2565  pShortToFixUp = (USHORT*)((PCHAR)Record + Offset);
2566  fixupArray->Array[i] = *pShortToFixUp;
2567  *pShortToFixUp = fixupArray->USN;
2568  Offset += Vcb->NtfsInfo.BytesPerSector;
2569  }
2570 
2571  return STATUS_SUCCESS;
2572 }
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:544
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:545
return STATUS_SUCCESS
Definition: btrfs.c:2725

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

◆ AddNewMftEntry()

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

Definition at line 1966 of file mft.c.

1970 {
1972  ULONGLONG MftIndex;
1974  ULONGLONG BitmapDataSize;
1975  ULONGLONG AttrBytesRead;
1978  ULONG LengthWritten;
1979  PNTFS_ATTR_CONTEXT BitmapContext;
1980  LARGE_INTEGER BitmapBits;
1981  UCHAR SystemReservedBits;
1982 
1983  DPRINT1("AddNewMftEntry(%p, %p, %p, %s)\n", FileRecord, DeviceExt, DestinationIndex, CanWait ? "TRUE" : "FALSE");
1984 
1985  // First, we have to read the mft's $Bitmap attribute
1986 
1987  // Find the attribute
1988  Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
1989  if (!NT_SUCCESS(Status))
1990  {
1991  DPRINT1("ERROR: Couldn't find $Bitmap attribute of master file table!\n");
1992  return Status;
1993  }
1994 
1995  // Get size of bitmap
1996  BitmapDataSize = AttributeDataLength(BitmapContext->pRecord);
1997 
1998  // RtlInitializeBitmap wants a ULONG-aligned pointer, and wants the memory passed to it to be a ULONG-multiple
1999  // Allocate a buffer for the $Bitmap attribute plus enough to ensure we can get a ULONG-aligned pointer
2000  BitmapBuffer = ExAllocatePoolWithTag(NonPagedPool, BitmapDataSize + sizeof(ULONG), TAG_NTFS);
2001  if (!BitmapBuffer)
2002  {
2003  ReleaseAttributeContext(BitmapContext);
2005  }
2006  RtlZeroMemory(BitmapBuffer, BitmapDataSize + sizeof(ULONG));
2007 
2008  // Get a ULONG-aligned pointer for the bitmap itself
2010 
2011  // read $Bitmap attribute
2012  AttrBytesRead = ReadAttribute(DeviceExt, BitmapContext, 0, (PCHAR)BitmapData, BitmapDataSize);
2013 
2014  if (AttrBytesRead != BitmapDataSize)
2015  {
2016  DPRINT1("ERROR: Unable to read $Bitmap attribute of master file table!\n");
2018  ReleaseAttributeContext(BitmapContext);
2020  }
2021 
2022  // We need to backup the bits for records 0x10 - 0x17 (3rd byte of bitmap) and mark these records
2023  // as in-use so we don't assign files to those indices. They're reserved for the system (e.g. ChkDsk).
2024  SystemReservedBits = BitmapData[2];
2025  BitmapData[2] = 0xff;
2026 
2027  // Calculate bit count
2028  BitmapBits.QuadPart = AttributeDataLength(DeviceExt->MFTContext->pRecord) /
2029  DeviceExt->NtfsInfo.BytesPerFileRecord;
2030  if (BitmapBits.HighPart != 0)
2031  {
2032  DPRINT1("\tFIXME: bitmap sizes beyond 32bits are not yet supported! (Your NTFS volume is too large)\n");
2035  ReleaseAttributeContext(BitmapContext);
2036  return STATUS_NOT_IMPLEMENTED;
2037  }
2038 
2039  // convert buffer into bitmap
2041 
2042  // set next available bit, preferrably after 23rd bit
2043  MftIndex = RtlFindClearBitsAndSet(&Bitmap, 1, 24);
2044  if ((LONG)MftIndex == -1)
2045  {
2046  DPRINT1("Couldn't find free space in MFT for file record, increasing MFT size.\n");
2047 
2049  ReleaseAttributeContext(BitmapContext);
2050 
2051  // Couldn't find a free record in the MFT, add some blank records and try again
2052  Status = IncreaseMftSize(DeviceExt, CanWait);
2053  if (!NT_SUCCESS(Status))
2054  {
2055  DPRINT1("ERROR: Couldn't find space in MFT for file or increase MFT size!\n");
2056  return Status;
2057  }
2058 
2059  return AddNewMftEntry(FileRecord, DeviceExt, DestinationIndex, CanWait);
2060  }
2061 
2062  DPRINT1("Creating file record at MFT index: %I64u\n", MftIndex);
2063 
2064  // update file record with index
2065  FileRecord->MFTRecordNumber = MftIndex;
2066 
2067  // [BitmapData should have been updated via RtlFindClearBitsAndSet()]
2068 
2069  // Restore the system reserved bits
2070  BitmapData[2] = SystemReservedBits;
2071 
2072  // write the bitmap back to the MFT's $Bitmap attribute
2073  Status = WriteAttribute(DeviceExt, BitmapContext, 0, BitmapData, BitmapDataSize, &LengthWritten, FileRecord);
2074  if (!NT_SUCCESS(Status))
2075  {
2076  DPRINT1("ERROR encountered when writing $Bitmap attribute!\n");
2078  ReleaseAttributeContext(BitmapContext);
2079  return Status;
2080  }
2081 
2082  // update the file record (write it to disk)
2083  Status = UpdateFileRecord(DeviceExt, MftIndex, FileRecord);
2084 
2085  if (!NT_SUCCESS(Status))
2086  {
2087  DPRINT1("ERROR: Unable to write file record!\n");
2089  ReleaseAttributeContext(BitmapContext);
2090  return Status;
2091  }
2092 
2093  *DestinationIndex = MftIndex;
2094 
2096  ReleaseAttributeContext(BitmapContext);
2097 
2098  return Status;
2099 }
signed char * PCHAR
Definition: retypes.h:7
NTSTATUS IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
Definition: mft.c:237
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:1966
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:1259
#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:1875
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:1009
#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:2725
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:203
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 193 of file mft.c.

194 {
195  if (AttrRecord->IsNonResident)
196  return AttrRecord->NonResident.AllocatedSize;
197  else
198  return ALIGN_UP_BY(AttrRecord->Resident.ValueLength, ATTR_RECORD_ALIGNMENT);
199 }
struct NTFS_ATTR_RECORD::@164::@167 NonResident
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:305
struct NTFS_ATTR_RECORD::@164::@166 Resident
UCHAR IsNonResident
Definition: ntfs.h:124
#define ALIGN_UP_BY(size, align)

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 2928 of file mft.c.

2940 {
2941  NTSTATUS Status;
2942  PINDEX_ENTRY_ATTRIBUTE IndexEntry;
2943  PNTFS_ATTR_CONTEXT IndexAllocationContext;
2944  PNTFS_ATTR_CONTEXT BitmapContext;
2945  PCHAR *BitmapMem;
2946  ULONG *BitmapPtr;
2948 
2949  DPRINT("BrowseIndexEntries(%p, %p, %p, %lu, %p, %p, %wZ, %lu, %lu, %s, %s, %p)\n",
2950  Vcb,
2951  MftRecord,
2952  IndexRecord,
2953  IndexBlockSize,
2954  FirstEntry,
2955  LastEntry,
2956  FileName,
2957  *StartEntry,
2958  *CurrentEntry,
2959  DirSearch ? "TRUE" : "FALSE",
2960  CaseSensitive ? "TRUE" : "FALSE",
2961  OutMFTIndex);
2962 
2963  // Find the $I30 index allocation, if there is one
2964  Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationContext, NULL);
2965  if (NT_SUCCESS(Status))
2966  {
2967  ULONGLONG BitmapLength;
2968  // Find the bitmap attribute for the index
2969  Status = FindAttribute(Vcb, MftRecord, AttributeBitmap, L"$I30", 4, &BitmapContext, NULL);
2970  if (!NT_SUCCESS(Status))
2971  {
2972  DPRINT1("Potential file system corruption detected!\n");
2973  ReleaseAttributeContext(IndexAllocationContext);
2974  return Status;
2975  }
2976 
2977  // Get the length of the bitmap attribute
2978  BitmapLength = AttributeDataLength(BitmapContext->pRecord);
2979 
2980  // Allocate memory for the bitmap, including some padding; RtlInitializeBitmap() wants a pointer
2981  // that's ULONG-aligned, and it wants the size of the memory allocated for it to be a ULONG-multiple.
2982  BitmapMem = ExAllocatePoolWithTag(NonPagedPool, BitmapLength + sizeof(ULONG), TAG_NTFS);
2983  if (!BitmapMem)
2984  {
2985  DPRINT1("Error: failed to allocate bitmap!");
2986  ReleaseAttributeContext(BitmapContext);
2987  ReleaseAttributeContext(IndexAllocationContext);
2989  }
2990 
2991  RtlZeroMemory(BitmapMem, BitmapLength + sizeof(ULONG));
2992 
2993  // RtlInitializeBitmap() wants a pointer that's ULONG-aligned.
2994  BitmapPtr = (PULONG)ALIGN_UP_BY((ULONG_PTR)BitmapMem, sizeof(ULONG));
2995 
2996  // Read the existing bitmap data
2997  Status = ReadAttribute(Vcb, BitmapContext, 0, (PCHAR)BitmapPtr, BitmapLength);
2998  if (!NT_SUCCESS(Status))
2999  {
3000  DPRINT1("ERROR: Failed to read bitmap attribute!\n");
3001  ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3002  ReleaseAttributeContext(BitmapContext);
3003  ReleaseAttributeContext(IndexAllocationContext);
3004  return Status;
3005  }
3006 
3007  // Initialize bitmap
3008  RtlInitializeBitMap(&Bitmap, BitmapPtr, BitmapLength * 8);
3009  }
3010  else
3011  {
3012  // Couldn't find an index allocation
3013  IndexAllocationContext = NULL;
3014  }
3015 
3016 
3017  // Loop through all Index Entries of index, starting with FirstEntry
3018  IndexEntry = FirstEntry;
3019  while (IndexEntry <= LastEntry)
3020  {
3021  // Does IndexEntry have a sub-node?
3022  if (IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
3023  {
3024  if (!(IndexRecord->Header.Flags & INDEX_ROOT_LARGE) || !IndexAllocationContext)
3025  {
3026  DPRINT1("Filesystem corruption detected!\n");
3027  }
3028  else
3029  {
3031  MftRecord,
3032  IndexBlockSize,
3033  FileName,
3034  IndexAllocationContext,
3035  &Bitmap,
3036  GetIndexEntryVCN(IndexEntry),
3037  StartEntry,
3038  CurrentEntry,
3039  DirSearch,
3040  CaseSensitive,
3041  OutMFTIndex);
3042  if (NT_SUCCESS(Status))
3043  {
3044  ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3045  ReleaseAttributeContext(BitmapContext);
3046  ReleaseAttributeContext(IndexAllocationContext);
3047  return Status;
3048  }
3049  }
3050  }
3051 
3052  // Are we done?
3053  if (IndexEntry->Flags & NTFS_INDEX_ENTRY_END)
3054  break;
3055 
3056  // If we've found a file whose index is greater than or equal to StartEntry that matches the search criteria
3057  if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= NTFS_FILE_FIRST_USER_FILE &&
3058  *CurrentEntry >= *StartEntry &&
3059  IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
3060  CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
3061  {
3062  *StartEntry = *CurrentEntry;
3063  *OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
3064  if (IndexAllocationContext)
3065  {
3066  ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3067  ReleaseAttributeContext(BitmapContext);
3068  ReleaseAttributeContext(IndexAllocationContext);
3069  }
3070  return STATUS_SUCCESS;
3071  }
3072 
3073  // Advance to the next index entry
3074  (*CurrentEntry) += 1;
3075  ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
3076  IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
3077  }
3078 
3079  if (IndexAllocationContext)
3080  {
3081  ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3082  ReleaseAttributeContext(BitmapContext);
3083  ReleaseAttributeContext(IndexAllocationContext);
3084  }
3085 
3087 }
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:2594
FILENAME_ATTRIBUTE FileName
Definition: ntfs.h:412
LONG NTSTATUS
Definition: precomp.h:26
USHORT Length
Definition: ntfs.h:408
union INDEX_ENTRY_ATTRIBUTE::@737 Data
Definition: ntfs.h:393
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
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:383
#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:410
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:1009
#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:2725
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:203
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:2783
struct INDEX_ENTRY_ATTRIBUTE::@737::@738 Directory
UCHAR NameType
Definition: ntfs.h:363

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 2783 of file mft.c.

2795 {
2796  PINDEX_BUFFER IndexRecord;
2797  ULONGLONG Offset;
2798  ULONG BytesRead;
2799  PINDEX_ENTRY_ATTRIBUTE FirstEntry;
2800  PINDEX_ENTRY_ATTRIBUTE LastEntry;
2801  PINDEX_ENTRY_ATTRIBUTE IndexEntry;
2802  ULONG NodeNumber;
2803  NTSTATUS Status;
2804 
2805  DPRINT("BrowseSubNodeIndexEntries(%p, %p, %lu, %wZ, %p, %p, %I64d, %lu, %lu, %s, %s, %p)\n",
2806  Vcb,
2807  MftRecord,
2808  IndexBlockSize,
2809  FileName,
2810  IndexAllocationContext,
2811  Bitmap,
2812  VCN,
2813  *StartEntry,
2814  *CurrentEntry,
2815  "FALSE",
2816  DirSearch ? "TRUE" : "FALSE",
2817  CaseSensitive ? "TRUE" : "FALSE",
2818  OutMFTIndex);
2819 
2820  // Calculate node number as VCN / Clusters per index record
2821  NodeNumber = VCN / (Vcb->NtfsInfo.BytesPerIndexRecord / Vcb->NtfsInfo.BytesPerCluster);
2822 
2823  // Is the bit for this node clear in the bitmap?
2824  if (!RtlCheckBit(Bitmap, NodeNumber))
2825  {
2826  DPRINT1("File system corruption detected, node with VCN %I64u is marked as deleted.\n", VCN);
2827  return STATUS_DATA_ERROR;
2828  }
2829 
2830  // Allocate memory for the index record
2831  IndexRecord = ExAllocatePoolWithTag(NonPagedPool, IndexBlockSize, TAG_NTFS);
2832  if (!IndexRecord)
2833  {
2834  DPRINT1("Unable to allocate memory for index record!\n");
2836  }
2837 
2838  // Calculate offset of index record
2839  Offset = VCN * Vcb->NtfsInfo.BytesPerCluster;
2840 
2841  // Read the index record
2842  BytesRead = ReadAttribute(Vcb, IndexAllocationContext, Offset, (PCHAR)IndexRecord, IndexBlockSize);
2843  if (BytesRead != IndexBlockSize)
2844  {
2845  DPRINT1("Unable to read index record!\n");
2846  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2847  return STATUS_UNSUCCESSFUL;
2848  }
2849 
2850  // Assert that we're dealing with an index record here
2851  ASSERT(IndexRecord->Ntfs.Type == NRH_INDX_TYPE);
2852 
2853  // Apply the fixup array to the index record
2854  Status = FixupUpdateSequenceArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
2855  if (!NT_SUCCESS(Status))
2856  {
2857  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2858  DPRINT1("Failed to apply fixup array!\n");
2859  return Status;
2860  }
2861 
2862  ASSERT(IndexRecord->Header.AllocatedSize + FIELD_OFFSET(INDEX_BUFFER, Header) == IndexBlockSize);
2863  FirstEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexRecord->Header + IndexRecord->Header.FirstEntryOffset);
2864  LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexRecord->Header + IndexRecord->Header.TotalSizeOfEntries);
2865  ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexRecord + IndexBlockSize));
2866 
2867  // Loop through all Index Entries of index, starting with FirstEntry
2868  IndexEntry = FirstEntry;
2869  while (IndexEntry <= LastEntry)
2870  {
2871  // Does IndexEntry have a sub-node?
2872  if (IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
2873  {
2874  if (!(IndexRecord->Header.Flags & INDEX_NODE_LARGE) || !IndexAllocationContext)
2875  {
2876  DPRINT1("Filesystem corruption detected!\n");
2877  }
2878  else
2879  {
2881  MftRecord,
2882  IndexBlockSize,
2883  FileName,
2884  IndexAllocationContext,
2885  Bitmap,
2886  GetIndexEntryVCN(IndexEntry),
2887  StartEntry,
2888  CurrentEntry,
2889  DirSearch,
2890  CaseSensitive,
2891  OutMFTIndex);
2892  if (NT_SUCCESS(Status))
2893  {
2894  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2895  return Status;
2896  }
2897  }
2898  }
2899 
2900  // Are we done?
2901  if (IndexEntry->Flags & NTFS_INDEX_ENTRY_END)
2902  break;
2903 
2904  // If we've found a file whose index is greater than or equal to StartEntry that matches the search criteria
2905  if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= NTFS_FILE_FIRST_USER_FILE &&
2906  *CurrentEntry >= *StartEntry &&
2907  IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
2908  CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
2909  {
2910  *StartEntry = *CurrentEntry;
2911  *OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
2912  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2913  return STATUS_SUCCESS;
2914  }
2915 
2916  // Advance to the next index entry
2917  (*CurrentEntry) += 1;
2918  ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
2919  IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
2920  }
2921 
2922  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2923 
2925 }
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:2594
FILENAME_ATTRIBUTE FileName
Definition: ntfs.h:412
LONG NTSTATUS
Definition: precomp.h:26
USHORT Length
Definition: ntfs.h:408
union INDEX_ENTRY_ATTRIBUTE::@737 Data
#define RtlCheckBit(BMH, BP)
Definition: rtlfuncs.h:3154
Definition: ntfs.h:393
#define NTFS_INDEX_ENTRY_END
Definition: ntfs.h:61
uint32_t ULONG_PTR
Definition: typedefs.h:63
_Out_ PUSHORT NodeNumber
Definition: iofuncs.h:2567
ULONG FirstEntryOffset
Definition: ntfs.h:369
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
Definition: Header.h:8
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:390
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:1909
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:410
ULONG TotalSizeOfEntries
Definition: ntfs.h:370
#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:1009
#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:388
#define INDEX_NODE_LARGE
Definition: ntfs.h:212
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:2725
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:2783
struct INDEX_ENTRY_ATTRIBUTE::@737::@738 Directory
UCHAR NameType
Definition: ntfs.h:363

Referenced by BrowseIndexEntries().

◆ CompareFileName()

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

Definition at line 2594 of file mft.c.

2598 {
2599  BOOLEAN Ret, Alloc = FALSE;
2600  UNICODE_STRING EntryName;
2601 
2602  EntryName.Buffer = IndexEntry->FileName.Name;
2603  EntryName.Length =
2604  EntryName.MaximumLength = IndexEntry->FileName.NameLength * sizeof(WCHAR);
2605 
2606  if (DirSearch)
2607  {
2608  UNICODE_STRING IntFileName;
2609  if (!CaseSensitive)
2610  {
2612  Alloc = TRUE;
2613  }
2614  else
2615  {
2616  IntFileName = *FileName;
2617  }
2618 
2619  Ret = FsRtlIsNameInExpression(&IntFileName, &EntryName, !CaseSensitive, NULL);
2620 
2621  if (Alloc)
2622  {
2623  RtlFreeUnicodeString(&IntFileName);
2624  }
2625 
2626  return Ret;
2627  }
2628  else
2629  {
2630  return (RtlCompareUnicodeString(FileName, &EntryName, !CaseSensitive) == 0);
2631  }
2632 }
#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:412
USHORT MaximumLength
Definition: env_spec_w32.h:370
WCHAR Name[1]
Definition: ntfs.h:364
UCHAR NameLength
Definition: ntfs.h:362
#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 
144  DPRINT("FindAttribute(%p, %p, 0x%x, %S, %lu, %p, %p)\n", Vcb, MftRecord, Type, Name, NameLength, AttrCtx, Offset);
145 
146  Found = FALSE;
147  Status = FindFirstAttribute(&Context, Vcb, MftRecord, FALSE, &Attribute);
148  while (NT_SUCCESS(Status))
149  {
150  if (Attribute->Type == Type && Attribute->NameLength == NameLength)
151  {
152  if (NameLength != 0)
153  {
154  PWCHAR AttrName;
155 
156  AttrName = (PWCHAR)((PCHAR)Attribute + Attribute->NameOffset);
157  DPRINT("%.*S, %.*S\n", Attribute->NameLength, AttrName, NameLength, Name);
158  if (RtlCompareMemory(AttrName, Name, NameLength * sizeof(WCHAR)) == (NameLength * sizeof(WCHAR)))
159  {
160  Found = TRUE;
161  }
162  }
163  else
164  {
165  Found = TRUE;
166  }
167 
168  if (Found)
169  {
170  /* Found it, fill up the context and return. */
171  DPRINT("Found context\n");
172  *AttrCtx = PrepareAttributeContext(Attribute);
173 
174  (*AttrCtx)->FileMFTIndex = MftRecord->MFTRecordNumber;
175 
176  if (Offset != NULL)
177  *Offset = Context.Offset;
178 
180  return STATUS_SUCCESS;
181  }
182  }
183 
184  Status = FindNextAttribute(&Context, &Attribute);
185  }
186 
189 }
signed char * PCHAR
Definition: retypes.h:7
#define TRUE
Definition: types.h:120
Type
Definition: Type.h:6
USHORT NameOffset
Definition: ntfs.h:126
ULONG MFTRecordNumber
Definition: ntfs.h:258
LONG NTSTATUS
Definition: precomp.h:26
ULONG Type
Definition: ntfs.h:122
uint16_t * PWCHAR
Definition: typedefs.h:54
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:1388
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define Vcb
Definition: cdprocs.h:1425
VOID FindCloseAttribute(PFIND_ATTR_CONTXT Context)
Definition: attrib.c:1422
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:1340
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
struct tagContext Context
Definition: acpixf.h:1012
return STATUS_SUCCESS
Definition: btrfs.c:2725
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465

Referenced by AddNewMftEntry(), AllocateIndexNode(), BrowseIndexEntries(), CreateBTreeFromIndex(), 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 1909 of file mft.c.

1911 {
1912  USHORT *USA;
1913  USHORT USANumber;
1914  USHORT USACount;
1915  USHORT *Block;
1916 
1917  USA = (USHORT*)((PCHAR)Record + Record->UsaOffset);
1918  USANumber = *(USA++);
1919  USACount = Record->UsaCount - 1; /* Exclude the USA Number. */
1920  Block = (USHORT*)((PCHAR)Record + Vcb->NtfsInfo.BytesPerSector - 2);
1921 
1922  DPRINT("FixupUpdateSequenceArray(%p, %p)\nUSANumber: %u\tUSACount: %u\n", Vcb, Record, USANumber, USACount);
1923 
1924  while (USACount)
1925  {
1926  if (*Block != USANumber)
1927  {
1928  DPRINT1("Mismatch with USA: %u read, %u expected\n" , *Block, USANumber);
1929  return STATUS_UNSUCCESSFUL;
1930  }
1931  *Block = *(USA++);
1932  Block = (USHORT*)((PCHAR)Block + Vcb->NtfsInfo.BytesPerSector);
1933  USACount--;
1934  }
1935 
1936  return STATUS_SUCCESS;
1937 }
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:2725

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

◆ IncreaseMftSize()

NTSTATUS IncreaseMftSize ( PDEVICE_EXTENSION  Vcb,
BOOLEAN  CanWait 
)

Definition at line 237 of file mft.c.

238 {
239  PNTFS_ATTR_CONTEXT BitmapContext;
240  LARGE_INTEGER BitmapSize;
242  LONGLONG BitmapSizeDifference;
243  ULONG NewRecords = ATTR_RECORD_ALIGNMENT * 8; // Allocate one new record for every bit of every byte we'll be adding to the bitmap
244  ULONG DataSizeDifference = Vcb->NtfsInfo.BytesPerFileRecord * NewRecords;
245  ULONG BitmapOffset;
247  ULONGLONG BitmapBytes;
248  ULONGLONG NewBitmapSize;
249  ULONGLONG FirstNewMftIndex;
251  ULONG LengthWritten;
252  PFILE_RECORD_HEADER BlankFileRecord;
253  ULONG i;
255 
256  DPRINT1("IncreaseMftSize(%p, %s)\n", Vcb, CanWait ? "TRUE" : "FALSE");
257 
258  // We need exclusive access to the mft while we change its size
259  if (!ExAcquireResourceExclusiveLite(&(Vcb->DirResource), CanWait))
260  {
261  return STATUS_CANT_WAIT;
262  }
263 
264  // Create a blank file record that will be used later
265  BlankFileRecord = NtfsCreateEmptyFileRecord(Vcb);
266  if (!BlankFileRecord)
267  {
268  DPRINT1("Error: Unable to create empty file record!\n");
270  }
271 
272  // Clear the flags (file record is not in use)
273  BlankFileRecord->Flags = 0;
274 
275  // Find the bitmap attribute of master file table
276  Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
277  if (!NT_SUCCESS(Status))
278  {
279  DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
280  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
281  ExReleaseResourceLite(&(Vcb->DirResource));
282  return Status;
283  }
284 
285  // Get size of Bitmap Attribute
286  BitmapSize.QuadPart = AttributeDataLength(BitmapContext->pRecord);
287 
288  // Calculate the new mft size
289  DataSize.QuadPart = AttributeDataLength(Vcb->MFTContext->pRecord) + DataSizeDifference;
290 
291  // Find the index of the first Mft entry that will be created
292  FirstNewMftIndex = AttributeDataLength(Vcb->MFTContext->pRecord) / Vcb->NtfsInfo.BytesPerFileRecord;
293 
294  // Determine how many bytes will make up the bitmap
295  BitmapBytes = DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord / 8;
296  if ((DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord) % 8 != 0)
297  BitmapBytes++;
298 
299  // Windows will always keep the number of bytes in a bitmap as a multiple of 8, so no bytes are wasted on slack
300  BitmapBytes = ALIGN_UP_BY(BitmapBytes, ATTR_RECORD_ALIGNMENT);
301 
302  // Determine how much we need to adjust the bitmap size (it's possible we don't)
303  BitmapSizeDifference = BitmapBytes - BitmapSize.QuadPart;
304  NewBitmapSize = max(BitmapSize.QuadPart + BitmapSizeDifference, BitmapSize.QuadPart);
305 
306  // Allocate memory for the bitmap
308  if (!BitmapBuffer)
309  {
310  DPRINT1("ERROR: Unable to allocate memory for bitmap attribute!\n");
311  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
312  ExReleaseResourceLite(&(Vcb->DirResource));
313  ReleaseAttributeContext(BitmapContext);
315  }
316 
317  // Zero the bytes we'll be adding
318  RtlZeroMemory(BitmapBuffer, NewBitmapSize);
319 
320  // Read the bitmap attribute
322  BitmapContext,
323  0,
325  BitmapSize.LowPart);
326  if (BytesRead != BitmapSize.LowPart)
327  {
328  DPRINT1("ERROR: Bytes read != Bitmap size!\n");
329  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
330  ExReleaseResourceLite(&(Vcb->DirResource));
332  ReleaseAttributeContext(BitmapContext);
334  }
335 
336  // Increase the mft size
337  Status = SetNonResidentAttributeDataLength(Vcb, Vcb->MFTContext, Vcb->MftDataOffset, Vcb->MasterFileTable, &DataSize);
338  if (!NT_SUCCESS(Status))
339  {
340  DPRINT1("ERROR: Failed to set size of $MFT data attribute!\n");
341  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
342  ExReleaseResourceLite(&(Vcb->DirResource));
344  ReleaseAttributeContext(BitmapContext);
345  return Status;
346  }
347 
348  // We'll need to find the bitmap again, because its offset will have changed after resizing the data attribute
349  ReleaseAttributeContext(BitmapContext);
350  Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, &BitmapOffset);
351  if (!NT_SUCCESS(Status))
352  {
353  DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
354  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
355  ExReleaseResourceLite(&(Vcb->DirResource));
356  return Status;
357  }
358 
359  // If the bitmap grew
360  if (BitmapSizeDifference > 0)
361  {
362  // Set the new bitmap size
363  BitmapSize.QuadPart = NewBitmapSize;
364  if (BitmapContext->pRecord->IsNonResident)
365  Status = SetNonResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize);
366  else
367  Status = SetResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize);
368 
369  if (!NT_SUCCESS(Status))
370  {
371  DPRINT1("ERROR: Failed to set size of bitmap attribute!\n");
372  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
373  ExReleaseResourceLite(&(Vcb->DirResource));
375  ReleaseAttributeContext(BitmapContext);
376  return Status;
377  }
378  }
379 
380  NtfsDumpFileAttributes(Vcb, Vcb->MasterFileTable);
381 
382  // Update the file record with the new attribute sizes
383  Status = UpdateFileRecord(Vcb, Vcb->VolumeFcb->MFTIndex, Vcb->MasterFileTable);
384  if (!NT_SUCCESS(Status))
385  {
386  DPRINT1("ERROR: Failed to update $MFT file record!\n");
387  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
388  ExReleaseResourceLite(&(Vcb->DirResource));
390  ReleaseAttributeContext(BitmapContext);
391  return Status;
392  }
393 
394  // Write out the new bitmap
395  Status = WriteAttribute(Vcb, BitmapContext, 0, BitmapBuffer, NewBitmapSize, &LengthWritten, Vcb->MasterFileTable);
396  if (!NT_SUCCESS(Status))
397  {
398  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
399  ExReleaseResourceLite(&(Vcb->DirResource));
401  ReleaseAttributeContext(BitmapContext);
402  DPRINT1("ERROR: Couldn't write to bitmap attribute of $MFT!\n");
403  return Status;
404  }
405 
406  // Create blank records for the new file record entries.
407  for (i = 0; i < NewRecords; i++)
408  {
409  Status = UpdateFileRecord(Vcb, FirstNewMftIndex + i, BlankFileRecord);
410  if (!NT_SUCCESS(Status))
411  {
412  DPRINT1("ERROR: Failed to write blank file record!\n");
413  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
414  ExReleaseResourceLite(&(Vcb->DirResource));
416  ReleaseAttributeContext(BitmapContext);
417  return Status;
418  }
419  }
420 
421  // Update the mft mirror
423 
424  // Cleanup
425  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
426  ExReleaseResourceLite(&(Vcb->DirResource));
428  ReleaseAttributeContext(BitmapContext);
429 
430  return Status;
431 }
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:835
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:1747
smooth NULL
Definition: ftsmooth.c:416
int64_t LONGLONG
Definition: typedefs.h:66
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:305
#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:700
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:1259
#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:1875
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1009
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:203
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4733
_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:2658
#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 486 of file mft.c.

491 {
492  PNTFS_ATTR_RECORD Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
494  PNTFS_ATTR_RECORD FinalAttribute;
495  ULONG OldAttributeLength = Destination->Length;
496  ULONG NextAttributeOffset;
497 
498  DPRINT1("InternalSetResidentAttributeLength( %p, %p, %p, %lu, %lu )\n", DeviceExt, AttrContext, FileRecord, AttrOffset, DataSize);
499 
500  ASSERT(!AttrContext->pRecord->IsNonResident);
501 
502  // Update ValueLength Field
503  Destination->Resident.ValueLength = DataSize;
504 
505  // Calculate the record length and end marker offset
506  Destination->Length = ALIGN_UP_BY(DataSize + AttrContext->pRecord->Resident.ValueOffset, ATTR_RECORD_ALIGNMENT);
507  NextAttributeOffset = AttrOffset + Destination->Length;
508 
509  // Ensure NextAttributeOffset is aligned to an 8-byte boundary
510  ASSERT(NextAttributeOffset % ATTR_RECORD_ALIGNMENT == 0);
511 
512  // Will the new attribute be larger than the old one?
513  if (Destination->Length > OldAttributeLength)
514  {
515  // Free the old copy of the attribute in the context, as it will be the wrong length
516  ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS);
517 
518  // Create a new copy of the attribute record for the context
519  AttrContext->pRecord = ExAllocatePoolWithTag(NonPagedPool, Destination->Length, TAG_NTFS);
520  if (!AttrContext->pRecord)
521  {
522  DPRINT1("Unable to allocate memory for attribute!\n");
524  }
525  RtlZeroMemory((PVOID)((ULONG_PTR)AttrContext->pRecord + OldAttributeLength), Destination->Length - OldAttributeLength);
526  RtlCopyMemory(AttrContext->pRecord, Destination, OldAttributeLength);
527  }
528 
529  // Are there attributes after this one that need to be moved?
530  if (NextAttribute->Type != AttributeEnd)
531  {
532  // Move the attributes after this one
533  FinalAttribute = MoveAttributes(DeviceExt, NextAttribute, NextAttributeOffset, (ULONG_PTR)Destination + Destination->Length);
534  }
535  else
536  {
537  // advance to the final "attribute," adjust for the changed length of the attribute we're resizing
538  FinalAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute - OldAttributeLength + Destination->Length);
539  }
540 
541  // Update pRecord's length
542  AttrContext->pRecord->Length = Destination->Length;
543  AttrContext->pRecord->Resident.ValueLength = DataSize;
544 
545  // set the file record end
546  SetFileRecordEnd(FileRecord, FinalAttribute, FILE_RECORD_END);
547 
548  //NtfsDumpFileRecord(DeviceExt, FileRecord);
549 
550  return STATUS_SUCCESS;
551 }
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:456
VOID SetFileRecordEnd(PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttrEnd, ULONG EndMarker)
Definition: mft.c:650
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:305
_In_ PUNICODE_STRING _Inout_ PUNICODE_STRING Destination
Definition: rtlfuncs.h:2875
#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:2725
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4733

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 456 of file mft.c.

460 {
461  // Get the size of all attributes after this one
462  ULONG MemBlockSize = 0;
463  PNTFS_ATTR_RECORD CurrentAttribute = FirstAttributeToMove;
464  ULONG CurrentOffset = FirstAttributeOffset;
465  PNTFS_ATTR_RECORD FinalAttribute;
466 
467  while (CurrentAttribute->Type != AttributeEnd && CurrentOffset < DeviceExt->NtfsInfo.BytesPerFileRecord)
468  {
469  CurrentOffset += CurrentAttribute->Length;
470  MemBlockSize += CurrentAttribute->Length;
471  CurrentAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)CurrentAttribute + CurrentAttribute->Length);
472  }
473 
474  FinalAttribute = (PNTFS_ATTR_RECORD)(MoveTo + MemBlockSize);
475  MemBlockSize += sizeof(ULONG) * 2; // Add the AttributeEnd and file record end
476 
477  ASSERT(MemBlockSize % ATTR_RECORD_ALIGNMENT == 0);
478 
479  // Move the attributes after this one
480  RtlMoveMemory((PCHAR)MoveTo, FirstAttributeToMove, MemBlockSize);
481 
482  return FinalAttribute;
483 }
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:305
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 2136 of file mft.c.

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

3242 {
3243  ULONG i, j;
3244 
3245  // dump binary data, 8 bytes at a time
3246  for (i = 0; i < Length; i += 8)
3247  {
3248  // display current offset, in hex
3249  DbgPrint("\t%03x\t", i);
3250 
3251  // display hex value of each of the next 8 bytes
3252  for (j = 0; j < 8; j++)
3253  DbgPrint("%02x ", *(PUCHAR)(Buffer + i + j));
3254  DbgPrint("\n");
3255  }
3256 }
#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 3278 of file mft.c.

3280 {
3281  ULONG i, j;
3282 
3283  // dump binary data, 8 bytes at a time
3284  for (i = 0; i < FileRecord->BytesInUse; i += 8)
3285  {
3286  // display current offset, in hex
3287  DbgPrint("\t%03x\t", i);
3288 
3289  // display hex value of each of the next 8 bytes
3290  for (j = 0; j < 8; j++)
3291  DbgPrint("%02x ", *(PUCHAR)((ULONG_PTR)FileRecord + i + j));
3292  DbgPrint("\n");
3293  }
3294 
3295  NtfsDumpFileAttributes(Vcb, FileRecord);
3296 }
#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:1747
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 3299 of file mft.c.

3306 {
3307  NTSTATUS Status;
3308 
3309  DPRINT("NtfsFindFileAt(%p, %wZ, %lu, %p, %p, %I64x, %s)\n",
3310  Vcb,
3311  SearchPattern,
3312  *FirstEntry,
3313  FileRecord,
3314  MFTIndex,
3315  CurrentMFTIndex,
3316  (CaseSensitive ? "TRUE" : "FALSE"));
3317 
3318  Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, SearchPattern, FirstEntry, TRUE, CaseSensitive, &CurrentMFTIndex);
3319  if (!NT_SUCCESS(Status))
3320  {
3321  DPRINT("NtfsFindFileAt: NtfsFindMftRecord() failed with status 0x%08lx\n", Status);
3322  return Status;
3323  }
3324 
3325  *FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
3326  if (*FileRecord == NULL)
3327  {
3328  DPRINT("NtfsFindFileAt: Can't allocate MFT record\n");
3330  }
3331 
3332  Status = ReadFileRecord(Vcb, CurrentMFTIndex, *FileRecord);
3333  if (!NT_SUCCESS(Status))
3334  {
3335  DPRINT("NtfsFindFileAt: Can't read MFT record\n");
3336  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, *FileRecord);
3337  return Status;
3338  }
3339 
3340  *MFTIndex = CurrentMFTIndex;
3341 
3342  return STATUS_SUCCESS;
3343 }
#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:3090
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:1575
return STATUS_SUCCESS
Definition: btrfs.c:2725

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 3090 of file mft.c.

3097 {
3098  PFILE_RECORD_HEADER MftRecord;
3099  PNTFS_ATTR_CONTEXT IndexRootCtx;
3100  PINDEX_ROOT_ATTRIBUTE IndexRoot;
3101  PCHAR IndexRecord;
3102  PINDEX_ENTRY_ATTRIBUTE IndexEntry, IndexEntryEnd;
3103  NTSTATUS Status;
3104  ULONG CurrentEntry = 0;
3105 
3106  DPRINT("NtfsFindMftRecord(%p, %I64d, %wZ, %lu, %s, %s, %p)\n",
3107  Vcb,
3108  MFTIndex,
3109  FileName,
3110  *FirstEntry,
3111  DirSearch ? "TRUE" : "FALSE",
3112  CaseSensitive ? "TRUE" : "FALSE",
3113  OutMFTIndex);
3114 
3115  MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
3116  if (MftRecord == NULL)
3117  {
3119  }
3120 
3121  Status = ReadFileRecord(Vcb, MFTIndex, MftRecord);
3122  if (!NT_SUCCESS(Status))
3123  {
3124  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3125  return Status;
3126  }
3127 
3128  ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
3129  Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
3130  if (!NT_SUCCESS(Status))
3131  {
3132  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3133  return Status;
3134  }
3135 
3136  IndexRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerIndexRecord, TAG_NTFS);
3137  if (IndexRecord == NULL)
3138  {
3139  ReleaseAttributeContext(IndexRootCtx);
3140  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3142  }
3143 
3144  ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, Vcb->NtfsInfo.BytesPerIndexRecord);
3145  IndexRoot = (PINDEX_ROOT_ATTRIBUTE)IndexRecord;
3146  IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)&IndexRoot->Header + IndexRoot->Header.FirstEntryOffset);
3147  /* Index root is always resident. */
3148  IndexEntryEnd = (PINDEX_ENTRY_ATTRIBUTE)(IndexRecord + IndexRoot->Header.TotalSizeOfEntries);
3149  ReleaseAttributeContext(IndexRootCtx);
3150 
3151  DPRINT("IndexRecordSize: %x IndexBlockSize: %x\n", Vcb->NtfsInfo.BytesPerIndexRecord, IndexRoot->SizeOfEntry);
3152 
3154  MftRecord,
3155  (PINDEX_ROOT_ATTRIBUTE)IndexRecord,
3156  IndexRoot->SizeOfEntry,
3157  IndexEntry,
3158  IndexEntryEnd,
3159  FileName,
3160  FirstEntry,
3161  &CurrentEntry,
3162  DirSearch,
3163  CaseSensitive,
3164  OutMFTIndex);
3165 
3166  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
3167  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3168 
3169  return Status;
3170 }
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:393
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:2928
ULONG FirstEntryOffset
Definition: ntfs.h:369
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
ULONG SizeOfEntry
Definition: ntfs.h:380
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define Vcb
Definition: cdprocs.h:1425
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:383
#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:370
Status
Definition: gdiplustypes.h:24
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1575
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:1009
#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 3231 of file mft.c.

3236 {
3237  return NtfsLookupFileAt(Vcb, PathName, CaseSensitive, FileRecord, MFTIndex, NTFS_FILE_ROOT);
3238 }
NTSTATUS NtfsLookupFileAt(PDEVICE_EXTENSION Vcb, PUNICODE_STRING PathName, BOOLEAN CaseSensitive, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex, ULONGLONG CurrentMFTIndex)
Definition: mft.c:3173
#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 3173 of file mft.c.

3179 {
3180  UNICODE_STRING Current, Remaining;
3181  NTSTATUS Status;
3182  ULONG FirstEntry = 0;
3183 
3184  DPRINT("NtfsLookupFileAt(%p, %wZ, %s, %p, %p, %I64x)\n",
3185  Vcb,
3186  PathName,
3187  CaseSensitive ? "TRUE" : "FALSE",
3188  FileRecord,
3189  MFTIndex,
3190  CurrentMFTIndex);
3191 
3192  FsRtlDissectName(*PathName, &Current, &Remaining);
3193 
3194  while (Current.Length != 0)
3195  {
3196  DPRINT("Current: %wZ\n", &Current);
3197 
3198  Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, &Current, &FirstEntry, FALSE, CaseSensitive, &CurrentMFTIndex);
3199  if (!NT_SUCCESS(Status))
3200  {
3201  return Status;
3202  }
3203 
3204  if (Remaining.Length == 0)
3205  break;
3206 
3207  FsRtlDissectName(Current, &Current, &Remaining);
3208  }
3209 
3210  *FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
3211  if (*FileRecord == NULL)
3212  {
3213  DPRINT("NtfsLookupFileAt: Can't allocate MFT record\n");
3215  }
3216 
3217  Status = ReadFileRecord(Vcb, CurrentMFTIndex, *FileRecord);
3218  if (!NT_SUCCESS(Status))
3219  {
3220  DPRINT("NtfsLookupFileAt: Can't read MFT record\n");
3221  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, *FileRecord);
3222  return Status;
3223  }
3224 
3225  *MFTIndex = CurrentMFTIndex;
3226 
3227  return STATUS_SUCCESS;
3228 }
#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:3090
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:1575
unsigned int ULONG
Definition: retypes.h:1
return STATUS_SUCCESS
Definition: btrfs.c:2725

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:1012
#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 1009 of file mft.c.

1014 {
1015  ULONGLONG LastLCN;
1016  PUCHAR DataRun;
1017  LONGLONG DataRunOffset;
1018  ULONGLONG DataRunLength;
1019  LONGLONG DataRunStartLCN;
1020  ULONGLONG CurrentOffset;
1021  ULONG ReadLength;
1022  ULONG AlreadyRead;
1023  NTSTATUS Status;
1024 
1025  //TEMPTEMP
1026  PUCHAR TempBuffer;
1027 
1028  if (!Context->pRecord->IsNonResident)
1029  {
1030  // We need to truncate Offset to a ULONG for pointer arithmetic
1031  // The check below should ensure that Offset is well within the range of 32 bits
1032  ULONG LittleOffset = (ULONG)Offset;
1033 
1034  // Ensure that offset isn't beyond the end of the attribute
1035  if (Offset > Context->pRecord->Resident.ValueLength)
1036  return 0;
1037  if (Offset + Length > Context->pRecord->Resident.ValueLength)
1038  Length = (ULONG)(Context->pRecord->Resident.ValueLength - Offset);
1039 
1040  RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Context->pRecord + Context->pRecord->Resident.ValueOffset + LittleOffset), Length);
1041  return Length;
1042  }
1043 
1044  /*
1045  * Non-resident attribute
1046  */
1047 
1048  /*
1049  * I. Find the corresponding start data run.
1050  */
1051 
1052  AlreadyRead = 0;
1053 
1054  // FIXME: Cache seems to be non-working. Disable it for now
1055  //if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * Volume->ClusterSize)
1056  if (0)
1057  {
1058  DataRun = Context->CacheRun;
1059  LastLCN = Context->CacheRunLastLCN;
1060  DataRunStartLCN = Context->CacheRunStartLCN;
1061  DataRunLength = Context->CacheRunLength;
1062  CurrentOffset = Context->CacheRunCurrentOffset;
1063  }
1064  else
1065  {
1066  //TEMPTEMP
1067  ULONG UsedBufferSize;
1068  TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
1069  if (TempBuffer == NULL)
1070  {
1072  }
1073 
1074  LastLCN = 0;
1075  CurrentOffset = 0;
1076 
1077  // This will be rewritten in the next iteration to just use the DataRuns MCB directly
1078  ConvertLargeMCBToDataRuns(&Context->DataRunsMCB,
1079  TempBuffer,
1080  Vcb->NtfsInfo.BytesPerFileRecord,
1081  &UsedBufferSize);
1082 
1083  DataRun = TempBuffer;
1084 
1085  while (1)
1086  {
1087  DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1088  if (DataRunOffset != -1)
1089  {
1090  /* Normal data run. */
1091  DataRunStartLCN = LastLCN + DataRunOffset;
1092  LastLCN = DataRunStartLCN;
1093  }
1094  else
1095  {
1096  /* Sparse data run. */
1097  DataRunStartLCN = -1;
1098  }
1099 
1100  if (Offset >= CurrentOffset &&
1101  Offset < CurrentOffset + (DataRunLength * Vcb->NtfsInfo.BytesPerCluster))
1102  {
1103  break;
1104  }
1105 
1106  if (*DataRun == 0)
1107  {
1108  ExFreePoolWithTag(TempBuffer, TAG_NTFS);
1109  return AlreadyRead;
1110  }
1111 
1112  CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1113  }
1114  }
1115 
1116  /*
1117  * II. Go through the run list and read the data
1118  */
1119 
1120  ReadLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset), Length);
1121  if (DataRunStartLCN == -1)
1122  {
1123  RtlZeroMemory(Buffer, ReadLength);
1125  }
1126  else
1127  {
1128  Status = NtfsReadDisk(Vcb->StorageDevice,
1129  DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster + Offset - CurrentOffset,
1130  ReadLength,
1131  Vcb->NtfsInfo.BytesPerSector,
1132  (PVOID)Buffer,
1133  FALSE);
1134  }
1135  if (NT_SUCCESS(Status))
1136  {
1137  Length -= ReadLength;
1138  Buffer += ReadLength;
1139  AlreadyRead += ReadLength;
1140 
1141  if (ReadLength == DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset))
1142  {
1143  CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1144  DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1145  if (DataRunOffset != (ULONGLONG)-1)
1146  {
1147  DataRunStartLCN = LastLCN + DataRunOffset;
1148  LastLCN = DataRunStartLCN;
1149  }
1150  else
1151  DataRunStartLCN = -1;
1152  }
1153 
1154  while (Length > 0)
1155  {
1156  ReadLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster, Length);
1157  if (DataRunStartLCN == -1)
1158  RtlZeroMemory(Buffer, ReadLength);
1159  else
1160  {
1161  Status = NtfsReadDisk(Vcb->StorageDevice,
1162  DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster,
1163  ReadLength,
1164  Vcb->NtfsInfo.BytesPerSector,
1165  (PVOID)Buffer,
1166  FALSE);
1167  if (!NT_SUCCESS(Status))
1168  break;
1169  }
1170 
1171  Length -= ReadLength;
1172  Buffer += ReadLength;
1173  AlreadyRead += ReadLength;
1174 
1175  /* We finished this request, but there still data in this data run. */
1176  if (Length == 0 && ReadLength != DataRunLength * Vcb->NtfsInfo.BytesPerCluster)
1177  break;
1178 
1179  /*
1180  * Go to next run in the list.
1181  */
1182 
1183  if (*DataRun == 0)
1184  break;
1185  CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1186  DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1187  if (DataRunOffset != -1)
1188  {
1189  /* Normal data run. */
1190  DataRunStartLCN = LastLCN + DataRunOffset;
1191  LastLCN = DataRunStartLCN;
1192  }
1193  else
1194  {
1195  /* Sparse data run. */
1196  DataRunStartLCN = -1;
1197  }
1198  } /* while */
1199 
1200  } /* if Disk */
1201 
1202  // TEMPTEMP
1203  if (Context->pRecord->IsNonResident)
1204  ExFreePoolWithTag(TempBuffer, TAG_NTFS);
1205 
1206  Context->CacheRun = DataRun;
1207  Context->CacheRunOffset = Offset + AlreadyRead;
1208  Context->CacheRunStartLCN = DataRunStartLCN;
1209  Context->CacheRunLength = DataRunLength;
1210  Context->CacheRunLastLCN = LastLCN;
1211  Context->CacheRunCurrentOffset = CurrentOffset;
1212 
1213  return AlreadyRead;
1214 }
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:2725
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 1575 of file mft.c.

1578 {
1580 
1581  DPRINT("ReadFileRecord(%p, %I64x, %p)\n", Vcb, index, file);
1582 
1583  BytesRead = ReadAttribute(Vcb, Vcb->MFTContext, index * Vcb->NtfsInfo.BytesPerFileRecord, (PCHAR)file, Vcb->NtfsInfo.BytesPerFileRecord);
1584  if (BytesRead != Vcb->NtfsInfo.BytesPerFileRecord)
1585  {
1586  DPRINT1("ReadFileRecord failed: %I64u read, %lu expected\n", BytesRead, Vcb->NtfsInfo.BytesPerFileRecord);
1587  return STATUS_PARTIAL_COPY;
1588  }
1589 
1590  /* Apply update sequence array fixups. */
1591  DPRINT("Sequence number: %u\n", file->SequenceNumber);
1592  return FixupUpdateSequenceArray(Vcb, &file->Ntfs);
1593 }
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:1909
ULONG ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1009
#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 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 2575 of file mft.c.

2579 {
2580  LARGE_INTEGER DiskSector;
2581 
2582  DiskSector.QuadPart = lcn;
2583 
2584  return NtfsReadSectors(Vcb->StorageDevice,
2585  DiskSector.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
2586  count * Vcb->NtfsInfo.SectorsPerCluster,
2587  Vcb->NtfsInfo.BytesPerSector,
2588  buffer,
2589  FALSE);
2590 }
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint buffer
Definition: glext.h:5915
#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
struct _LARGE_INTEGER::@2192 u
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 559 of file mft.c.

565 {
567 
568  DPRINT1("SetAttributeDataLength(%p, %p, %p, %lu, %p, %I64u)\n",
569  FileObject,
570  Fcb,
571  AttrContext,
572  AttrOffset,
573  FileRecord,
574  DataSize->QuadPart);
575 
576  // are we truncating the file?
577  if (DataSize->QuadPart < AttributeDataLength(AttrContext->pRecord))
578  {
579  if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer, DataSize))
580  {
581  DPRINT1("Can't truncate a memory-mapped file!\n");
583  }
584  }
585 
586  if (AttrContext->pRecord->IsNonResident)
587  {
589  AttrContext,
590  AttrOffset,
591  FileRecord,
592  DataSize);
593  }
594  else
595  {
596  // resident attribute
598  AttrContext,
599  AttrOffset,
600  FileRecord,
601  DataSize);
602  }
603 
604  if (!NT_SUCCESS(Status))
605  {
606  DPRINT1("ERROR: Failed to set size of attribute!\n");
607  return Status;
608  }
609 
610  //NtfsDumpFileAttributes(Fcb->Vcb, FileRecord);
611 
612  // write the updated file record back to disk
613  Status = UpdateFileRecord(Fcb->Vcb, Fcb->MFTIndex, FileRecord);
614 
615  if (NT_SUCCESS(Status))
616  {
617  if (AttrContext->pRecord->IsNonResident)
618  Fcb->RFCB.AllocationSize.QuadPart = AttrContext->pRecord->NonResident.AllocatedSize;
619  else
624  }
625 
626  return STATUS_SUCCESS;
627 }
BOOLEAN NTAPI MmCanFileBeTruncated(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN PLARGE_INTEGER NewFileSize)
Definition: section.c:4718
LONG NTSTATUS
Definition: precomp.h:26
ULONGLONG MFTIndex
Definition: ntfs.h:523
NTSTATUS SetResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:835
#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:501
#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:700
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:1875
#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:2725
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:203
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4733
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 650 of file mft.c.

653 {
654  // Ensure AttrEnd is aligned on an 8-byte boundary, relative to FileRecord
655  ASSERT(((ULONG_PTR)AttrEnd - (ULONG_PTR)FileRecord) % ATTR_RECORD_ALIGNMENT == 0);
656 
657  // mark the end of attributes
658  AttrEnd->Type = AttributeEnd;
659 
660  // Restore the "file-record-end marker." The value is never checked but this behavior is consistent with Win2k3.
661  AttrEnd->Length = EndMarker;
662 
663  // recalculate bytes in use
664  FileRecord->BytesInUse = (ULONG_PTR)AttrEnd - (ULONG_PTR)FileRecord + sizeof(ULONG) * 2;
665 }
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:305
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 700 of file mft.c.

705 {
707  ULONG BytesPerCluster = Vcb->NtfsInfo.BytesPerCluster;
708  ULONGLONG AllocationSize = ROUND_UP(DataSize->QuadPart, BytesPerCluster);
709  PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
710  ULONG ExistingClusters = AttrContext->pRecord->NonResident.AllocatedSize / BytesPerCluster;
711 
712  ASSERT(AttrContext->pRecord->IsNonResident);
713 
714  // do we need to increase the allocation size?
715  if (AttrContext->pRecord->NonResident.AllocatedSize < AllocationSize)
716  {
717  ULONG ClustersNeeded = (AllocationSize / BytesPerCluster) - ExistingClusters;
718  LARGE_INTEGER LastClusterInDataRun;
719  ULONG NextAssignedCluster;
720  ULONG AssignedClusters;
721 
722  if (ExistingClusters == 0)
723  {
724  LastClusterInDataRun.QuadPart = 0;
725  }
726  else
727  {
728  if (!FsRtlLookupLargeMcbEntry(&AttrContext->DataRunsMCB,
729  (LONGLONG)AttrContext->pRecord->NonResident.HighestVCN,
730  (PLONGLONG)&LastClusterInDataRun.QuadPart,
731  NULL,
732  NULL,
733  NULL,
734  NULL))
735  {
736  DPRINT1("Error looking up final large MCB entry!\n");
737 
738  // Most likely, HighestVCN went above the largest mapping
739  DPRINT1("Highest VCN of record: %I64u\n", AttrContext->pRecord->NonResident.HighestVCN);
741  }
742  }
743 
744  DPRINT("LastClusterInDataRun: %I64u\n", LastClusterInDataRun.QuadPart);
745  DPRINT("Highest VCN of record: %I64u\n", AttrContext->pRecord->NonResident.HighestVCN);
746 
747  while (ClustersNeeded > 0)
748  {
750  LastClusterInDataRun.LowPart + 1,
751  ClustersNeeded,
752  &NextAssignedCluster,
753  &AssignedClusters);
754 
755  if (!NT_SUCCESS(Status))
756  {
757  DPRINT1("Error: Unable to allocate requested clusters!\n");
758  return Status;
759  }
760 
761  // now we need to add the clusters we allocated to the data run
762  Status = AddRun(Vcb, AttrContext, AttrOffset, FileRecord, NextAssignedCluster, AssignedClusters);
763  if (!NT_SUCCESS(Status))
764  {
765  DPRINT1("Error: Unable to add data run!\n");
766  return Status;
767  }
768 
769  ClustersNeeded -= AssignedClusters;
770  LastClusterInDataRun.LowPart = NextAssignedCluster + AssignedClusters - 1;
771  }
772  }
773  else if (AttrContext->pRecord->NonResident.AllocatedSize > AllocationSize)
774  {
775  // shrink allocation size
776  ULONG ClustersToFree = ExistingClusters - (AllocationSize / BytesPerCluster);
777  Status = FreeClusters(Vcb, AttrContext, AttrOffset, FileRecord, ClustersToFree);
778  }
779 
780  // TODO: is the file compressed, encrypted, or sparse?
781 
782  AttrContext->pRecord->NonResident.AllocatedSize = AllocationSize;
783  AttrContext->pRecord->NonResident.DataSize = DataSize->QuadPart;
784  AttrContext->pRecord->NonResident.InitializedSize = DataSize->QuadPart;
785 
786  DestinationAttribute->NonResident.AllocatedSize = AllocationSize;
787  DestinationAttribute->NonResident.DataSize = DataSize->QuadPart;
788  DestinationAttribute->NonResident.InitializedSize = DataSize->QuadPart;
789 
790  // HighestVCN seems to be set incorrectly somewhere. Apply a hack-fix to reset it.
791  // HACKHACK FIXME: Fix for sparse files; this math won't work in that case.
792  AttrContext->pRecord->NonResident.HighestVCN = ((ULONGLONG)AllocationSize / Vcb->NtfsInfo.BytesPerCluster) - 1;
793  DestinationAttribute->NonResident.HighestVCN = AttrContext->pRecord->NonResident.HighestVCN;
794 
795  DPRINT("Allocated Size: %I64u\n", DestinationAttribute->NonResident.AllocatedSize);
796 
797  return Status;
798 }
#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
struct NTFS_ATTR_RECORD::@164::@167 NonResident
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
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
return STATUS_SUCCESS
Definition: btrfs.c:2725
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4733
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 835 of file mft.c.

840 {
842 
843  // find the next attribute
844  ULONG NextAttributeOffset = AttrOffset + AttrContext->pRecord->Length;
845  PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((PCHAR)FileRecord + NextAttributeOffset);
846 
847  ASSERT(!AttrContext->pRecord->IsNonResident);
848 
849  //NtfsDumpFileAttributes(Vcb, FileRecord);
850 
851  // Do we need to increase the data length?
852  if (DataSize->QuadPart > AttrContext->pRecord->Resident.ValueLength)
853  {
854  // There's usually padding at the end of a record. Do we need to extend past it?
855  ULONG MaxValueLength = AttrContext->pRecord->Length - AttrContext->pRecord->Resident.ValueOffset;
856  if (MaxValueLength < DataSize->LowPart)
857  {
858  // If this is the last attribute, we could move the end marker to the very end of the file record
859  MaxValueLength += Vcb->NtfsInfo.BytesPerFileRecord - NextAttributeOffset - (sizeof(ULONG) * 2);
860 
861  if (MaxValueLength < DataSize->LowPart || NextAttribute->Type != AttributeEnd)
862  {
863  // convert attribute to non-resident
864  PNTFS_ATTR_RECORD Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
865  PNTFS_ATTR_RECORD NewRecord;
866  LARGE_INTEGER AttribDataSize;
867  PVOID AttribData;
868  ULONG NewRecordLength;
869  ULONG EndAttributeOffset;
870  ULONG LengthWritten;
871 
872  DPRINT1("Converting attribute to non-resident.\n");
873 
874  AttribDataSize.QuadPart = AttrContext->pRecord->Resident.ValueLength;
875 
876  // Is there existing data we need to back-up?
877  if (AttribDataSize.QuadPart > 0)
878  {
879  AttribData = ExAllocatePoolWithTag(NonPagedPool, AttribDataSize.QuadPart, TAG_NTFS);
880  if (AttribData == NULL)
881  {
882  DPRINT1("ERROR: Couldn't allocate memory for attribute data. Can't migrate to non-resident!\n");
884  }
885 
886  // read data to temp buffer
887  Status = ReadAttribute(Vcb, AttrContext, 0, AttribData, AttribDataSize.QuadPart);
888  if (!NT_SUCCESS(Status))
889  {
890  DPRINT1("ERROR: Unable to read attribute before migrating!\n");
891  ExFreePoolWithTag(AttribData, TAG_NTFS);
892  return Status;
893  }
894  }
895 
896  // Start by turning this attribute into a 0-length, non-resident attribute, then enlarge it.
897 
898  // The size of a 0-length, non-resident attribute will be 0x41 + the size of the attribute name, aligned to an 8-byte boundary
899  NewRecordLength = ALIGN_UP_BY(0x41 + (AttrContext->pRecord->NameLength * sizeof(WCHAR)), ATTR_RECORD_ALIGNMENT);
900 
901  // Create a new attribute record that will store the 0-length, non-resident attribute
902  NewRecord = ExAllocatePoolWithTag(NonPagedPool, NewRecordLength, TAG_NTFS);
903 
904  // Zero out the NonResident structure
905  RtlZeroMemory(NewRecord, NewRecordLength);
906 
907  // Copy the data that's common to both non-resident and resident attributes
908  RtlCopyMemory(NewRecord, AttrContext->pRecord, FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.ValueLength));
909 
910  // if there's a name
911  if (AttrContext->pRecord->NameLength != 0)
912  {
913  // copy the name
914  // An attribute name will be located at offset 0x18 for a resident attribute, 0x40 for non-resident
915  RtlCopyMemory((PCHAR)((ULONG_PTR)NewRecord + 0x40),
916  (PCHAR)((ULONG_PTR)AttrContext->pRecord + 0x18),
917  AttrContext->pRecord->NameLength * sizeof(WCHAR));
918  }
919 
920  // update the mapping pairs offset, which will be 0x40 (size of a non-resident header) + length in bytes of the name
921  NewRecord->NonResident.MappingPairsOffset = 0x40 + (AttrContext->pRecord->NameLength * sizeof(WCHAR));
922 
923  // update the end of the file record
924  // calculate position of end markers (1 byte for empty data run)
925  EndAttributeOffset = AttrOffset + NewRecord->NonResident.MappingPairsOffset + 1;
926  EndAttributeOffset = ALIGN_UP_BY(EndAttributeOffset, ATTR_RECORD_ALIGNMENT);
927 
928  // Update the length
929  NewRecord->Length = EndAttributeOffset - AttrOffset;
930 
931  ASSERT(NewRecord->Length == NewRecordLength);
932 
933  // Copy the new attribute record into the file record
934  RtlCopyMemory(Destination, NewRecord, NewRecord->Length);
935 
936  // Update the file record end
937  SetFileRecordEnd(FileRecord,
938  (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + EndAttributeOffset),
940 
941  // Initialize the MCB, potentially catch an exception
942  _SEH2_TRY
943  {
944  FsRtlInitializeLargeMcb(&AttrContext->DataRunsMCB, NonPagedPool);
945  }
947  {
948  DPRINT1("Unable to create LargeMcb!\n");
949  if (AttribDataSize.QuadPart > 0)
950  ExFreePoolWithTag(AttribData, TAG_NTFS);
951  ExFreePoolWithTag(NewRecord, TAG_NTFS);
953  } _SEH2_END;
954 
955  // Mark the attribute as non-resident (we wait until after we know the LargeMcb was initialized)
956  NewRecord->IsNonResident = Destination->IsNonResident = 1;
957 
958  // Update file record on disk
959  Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord);
960  if (!NT_SUCCESS(Status))
961  {
962  DPRINT1("ERROR: Couldn't update file record to continue migration!\n");
963  if (AttribDataSize.QuadPart > 0)
964  ExFreePoolWithTag(AttribData, TAG_NTFS);
965  ExFreePoolWithTag(NewRecord, TAG_NTFS);
966  return Status;
967  }
968 
969  // Now we need to free the old copy of the attribute record in the context and replace it with the new one
970  ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS);
971  AttrContext->pRecord = NewRecord;
972 
973  // Now we can treat the attribute as non-resident and enlarge it normally
974  Status = SetNonResidentAttributeDataLength(Vcb, AttrContext, AttrOffset, FileRecord, DataSize);
975  if (!NT_SUCCESS(Status))
976  {
977  DPRINT1("ERROR: Unable to migrate resident attribute!\n");
978  if (AttribDataSize.QuadPart > 0)
979  ExFreePoolWithTag(AttribData, TAG_NTFS);
980  return Status;
981  }
982 
983  // restore the back-up attribute, if we made one
984  if (AttribDataSize.QuadPart > 0)
985  {
986  Status = WriteAttribute(Vcb, AttrContext, 0, AttribData, AttribDataSize.QuadPart, &LengthWritten, FileRecord);
987  if (!NT_SUCCESS(Status))
988  {
989  DPRINT1("ERROR: Unable to write attribute data to non-resident clusters during migration!\n");
990  // TODO: Reverse migration so no data is lost
991  ExFreePoolWithTag(AttribData, TAG_NTFS);
992  return Status;
993  }
994 
995  ExFreePoolWithTag(AttribData, TAG_NTFS);
996  }
997  }
998  }
999  }
1000 
1001  // set the new length of the resident attribute (if we didn't migrate it)
1002  if (!AttrContext->pRecord->IsNonResident)
1003  return InternalSetResidentAttributeLength(Vcb, AttrContext, FileRecord, AttrOffset, DataSize->LowPart);
1004 
1005  return STATUS_SUCCESS;
1006 }
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
struct NTFS_ATTR_RECORD::@164::@167 NonResident
VOID SetFileRecordEnd(PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttrEnd, ULONG EndMarker)
Definition: mft.c:650
NTSTATUS InternalSetResidentAttributeLength(PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_CONTEXT AttrContext, PFILE_RECORD_HEADER FileRecord, ULONG AttrOffset, ULONG DataSize)
Definition: mft.c:486
#define _SEH2_YIELD(STMT_)
Definition: pseh2_64.h:8
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:305
__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:2875
NTSTATUS SetNonResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:700
#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:1259
#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
NTSTATUS UpdateFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1875
#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:1009
#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:2725
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4733
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 1604 of file mft.c.

1611 {
1612  PFILE_RECORD_HEADER MftRecord;
1613  PNTFS_ATTR_CONTEXT IndexRootCtx;
1614  PINDEX_ROOT_ATTRIBUTE IndexRoot;
1615  PCHAR IndexRecord;
1616  PINDEX_ENTRY_ATTRIBUTE IndexEntry, IndexEntryEnd;
1617  NTSTATUS Status;
1618  ULONG CurrentEntry = 0;
1619 
1620  DPRINT("UpdateFileNameRecord(%p, %I64d, %wZ, %s, %I64u, %I64u, %s)\n",
1621  Vcb,
1622  ParentMFTIndex,
1623  FileName,
1624  DirSearch ? "TRUE" : "FALSE",
1625  NewDataSize,
1626  NewAllocationSize,
1627  CaseSensitive ? "TRUE" : "FALSE");
1628 
1629  MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
1630  if (MftRecord == NULL)
1631  {
1633  }
1634 
1635  Status = ReadFileRecord(Vcb, ParentMFTIndex, MftRecord);
1636  if (!NT_SUCCESS(Status))
1637  {
1638  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1639  return Status;
1640  }
1641 
1642  ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
1643  Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
1644  if (!NT_SUCCESS(Status))
1645  {
1646  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1647  return Status;
1648  }
1649 
1650  IndexRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerIndexRecord, TAG_NTFS);
1651  if (IndexRecord == NULL)
1652  {
1653  ReleaseAttributeContext(IndexRootCtx);
1654  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1656  }
1657 
1658  Status = ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, AttributeDataLength(IndexRootCtx->pRecord));
1659  if (!NT_SUCCESS(Status))
1660  {
1661  DPRINT1("ERROR: Failed to read Index Root!\n");
1662  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
1663  ReleaseAttributeContext(IndexRootCtx);
1664  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1665  return Status;
1666  }
1667 
1668  IndexRoot = (PINDEX_ROOT_ATTRIBUTE)IndexRecord;
1669  IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)&IndexRoot->Header + IndexRoot->Header.FirstEntryOffset);
1670  // Index root is always resident.
1671  IndexEntryEnd = (PINDEX_ENTRY_ATTRIBUTE)(IndexRecord + IndexRoot->Header.TotalSizeOfEntries);
1672 
1673  DPRINT("IndexRecordSize: %x IndexBlockSize: %x\n", Vcb->NtfsInfo.BytesPerIndexRecord, IndexRoot->SizeOfEntry);
1674 
1676  MftRecord,
1677  IndexRecord,
1678  IndexRoot->SizeOfEntry,
1679  IndexEntry,
1680  IndexEntryEnd,
1681  FileName,
1682  &CurrentEntry,
1683  &CurrentEntry,
1684  DirSearch,
1685  NewDataSize,
1686  NewAllocationSize,
1687  CaseSensitive);
1688 
1689  if (Status == STATUS_PENDING)
1690  {
1691  // we need to write the index root attribute back to disk
1692  ULONG LengthWritten;
1693  Status = WriteAttribute(Vcb, IndexRootCtx, 0, (PUCHAR)IndexRecord, AttributeDataLength(IndexRootCtx->pRecord), &LengthWritten, MftRecord);
1694  if (!NT_SUCCESS(Status))
1695  {
1696  DPRINT1("ERROR: Couldn't update Index Root!\n");
1697  }
1698 
1699  }
1700 
1701  ReleaseAttributeContext(IndexRootCtx);
1702  ExFreePoolWithTag(IndexRecord, TAG_NTFS);
1703  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1704 
1705  return Status;
1706 }
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:393
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:369
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
ULONG SizeOfEntry
Definition: ntfs.h:380
#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:383
#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:1259
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static const WCHAR L[]
Definition: oid.c:1250
ULONG TotalSizeOfEntries
Definition: ntfs.h:370
Status
Definition: gdiplustypes.h:24
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1575
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:1009
#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:203
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:1714

Referenced by NtfsSetEndOfFile(), and NtfsWriteFile().

◆ UpdateFileRecord()

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

Definition at line 1875 of file mft.c.

1878 {
1881 
1882  DPRINT("UpdateFileRecord(%p, 0x%I64x, %p)\n", Vcb, MftIndex, FileRecord);
1883 
1884  // Add the fixup array to prepare the data for writing to disk
1885  AddFixupArray(Vcb, &FileRecord->Ntfs);
1886 
1887  // write the file record to the master file table
1889  Vcb->MFTContext,
1890  MftIndex * Vcb->NtfsInfo.BytesPerFileRecord,
1891  (const PUCHAR)FileRecord,
1892  Vcb->NtfsInfo.BytesPerFileRecord,
1893  &BytesWritten,
1894  FileRecord);
1895 
1896  if (!NT_SUCCESS(Status))
1897  {
1898  DPRINT1("UpdateFileRecord failed: %lu written, %lu expected\n", BytesWritten, Vcb->NtfsInfo.BytesPerFileRecord);
1899  }
1900 
1901  // remove the fixup array (so the file record pointer can still be used)
1902  FixupUpdateSequenceArray(Vcb, &FileRecord->Ntfs);
1903 
1904  return Status;
1905 }
NTSTATUS AddFixupArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:2547
_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:1909
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:1259
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:2725

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 1714 of file mft.c.

1727 {
1728  NTSTATUS Status;
1729  ULONG RecordOffset;
1730  PINDEX_ENTRY_ATTRIBUTE IndexEntry;
1731  PNTFS_ATTR_CONTEXT IndexAllocationCtx;
1732  ULONGLONG IndexAllocationSize;
1733  PINDEX_BUFFER IndexBuffer;
1734 
1735  DPRINT("UpdateIndexEntrySize(%p, %p, %p, %lu, %p, %p, %wZ, %lu, %lu, %s, %I64u, %I64u, %s)\n",
1736  Vcb,
1737  MftRecord,
1738  IndexRecord,
1739  IndexBlockSize,
1740  FirstEntry,
1741  LastEntry,
1742  FileName,
1743  *StartEntry,
1744  *CurrentEntry,
1745  DirSearch ? "TRUE" : "FALSE",
1746  NewDataSize,
1747  NewAllocatedSize,
1748  CaseSensitive ? "TRUE" : "FALSE");
1749 
1750  // find the index entry responsible for the file we're trying to update
1751  IndexEntry = FirstEntry;
1752  while (IndexEntry < LastEntry &&
1753  !(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
1754  {
1755  if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) > NTFS_FILE_FIRST_USER_FILE &&
1756  *CurrentEntry >= *StartEntry &&
1757  IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
1758  CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
1759  {
1760  *StartEntry = *CurrentEntry;
1761  IndexEntry->FileName.DataSize = NewDataSize;
1762  IndexEntry->FileName.AllocatedSize = NewAllocatedSize;
1763  // indicate that the caller will still need to write the structure to the disk
1764  return STATUS_PENDING;
1765  }
1766 
1767  (*CurrentEntry) += 1;
1768  ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
1769  IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
1770  }
1771 
1772  /* If we're already browsing a subnode */
1773  if (IndexRecord == NULL)
1774  {
1776  }
1777 
1778  /* If there's no subnode */
1779  if (!(IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE))
1780  {
1782  }
1783 
1784  Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationCtx, NULL);
1785  if (!NT_SUCCESS(Status))
1786  {
1787  DPRINT("Corrupted filesystem!\n");
1788  return Status;
1789  }
1790 
1791  IndexAllocationSize = AttributeDataLength(IndexAllocationCtx->pRecord);
1793  for (RecordOffset = 0; RecordOffset < IndexAllocationSize; RecordOffset += IndexBlockSize)
1794  {
1795  ReadAttribute(Vcb, IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
1796  Status = FixupUpdateSequenceArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
1797  if (!NT_SUCCESS(Status))
1798  {
1799  break;
1800  }
1801 
1802  IndexBuffer = (PINDEX_BUFFER)IndexRecord;
1803  ASSERT(IndexBuffer->Ntfs.Type == NRH_INDX_TYPE);
1804  ASSERT(IndexBuffer->Header.AllocatedSize + FIELD_OFFSET(INDEX_BUFFER, Header) == IndexBlockSize);
1805  FirstEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.FirstEntryOffset);
1806  LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.TotalSizeOfEntries);
1807  ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexBuffer + IndexBlockSize));
1808 
1810  NULL,
1811  NULL,
1812  0,
1813  FirstEntry,
1814  LastEntry,
1815  FileName,
1816  StartEntry,
1817  CurrentEntry,
1818  DirSearch,
1819  NewDataSize,
1820  NewAllocatedSize,
1821  CaseSensitive);
1822  if (Status == STATUS_PENDING)
1823  {
1824  // write the index record back to disk
1825  ULONG Written;
1826 
1827  // first we need to update the fixup values for the index block
1828  Status = AddFixupArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
1829  if (!NT_SUCCESS(Status))
1830  {
1831  DPRINT1("Error: Failed to update fixup sequence array!\n");
1832  break;
1833  }
1834 
1835  Status = WriteAttribute(Vcb, IndexAllocationCtx, RecordOffset, (const PUCHAR)IndexRecord, IndexBlockSize, &Written, MftRecord);
1836  if (!NT_SUCCESS(Status))
1837  {
1838  DPRINT1("ERROR Performing write!\n");
1839  break;
1840  }
1841 
1843  break;
1844  }
1845  if (NT_SUCCESS(Status))
1846  {
1847  break;
1848  }
1849  }
1850 
1851  ReleaseAttributeContext(IndexAllocationCtx);
1852  return Status;
1853 }
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:350
NTSTATUS AddFixupArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:2547
BOOLEAN CompareFileName(PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive)
Definition: mft.c:2594
FILENAME_ATTRIBUTE FileName
Definition: ntfs.h:412
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
USHORT Length
Definition: ntfs.h:408
union INDEX_ENTRY_ATTRIBUTE::@737 Data
Definition: ntfs.h:393
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
ULONG FirstEntryOffset
Definition: ntfs.h:369
Definition: Header.h:8
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:390
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
ULONGLONG DataSize
Definition: ntfs.h:351
#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:1909
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:1259
USHORT Flags
Definition: ntfs.h:410
static const WCHAR L[]
Definition: oid.c:1250
ULONG TotalSizeOfEntries
Definition: ntfs.h:370
#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:1009
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:388
return STATUS_SUCCESS
Definition: btrfs.c:2725
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:203
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:1714
struct INDEX_ENTRY_ATTRIBUTE::@737::@738 Directory
UCHAR NameType
Definition: ntfs.h:363

Referenced by UpdateFileNameRecord(), and UpdateIndexEntryFileNameSize().

◆ UpdateMftMirror()

NTSTATUS UpdateMftMirror ( PNTFS_VCB  Vcb)

Definition at line 2658 of file mft.c.

2659 {
2660  PFILE_RECORD_HEADER MirrorFileRecord;
2661  PNTFS_ATTR_CONTEXT MirrDataContext;
2662  PNTFS_ATTR_CONTEXT MftDataContext;
2663  PCHAR DataBuffer;
2665  NTSTATUS Status;
2666  ULONG BytesRead;
2667  ULONG LengthWritten;
2668 
2669  // Allocate memory for the Mft mirror file record
2670  MirrorFileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
2671  if (!MirrorFileRecord)
2672  {
2673  DPRINT1("Error: Failed to allocate memory for $MFTMirr!\n");
2675  }
2676 
2677  // Read the Mft Mirror file record
2678  Status = ReadFileRecord(Vcb, NTFS_FILE_MFTMIRR, MirrorFileRecord);
2679  if (!NT_SUCCESS(Status))
2680  {
2681  DPRINT1("ERROR: Failed to read $MFTMirr!\n");
2682  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2683  return Status;
2684  }
2685 
2686  // Find the $DATA attribute of $MFTMirr
2687  Status = FindAttribute(Vcb, MirrorFileRecord, AttributeData, L"", 0, &MirrDataContext, NULL);
2688  if (!NT_SUCCESS(Status))
2689  {
2690  DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
2691  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2692  return Status;
2693  }
2694 
2695  // Find the $DATA attribute of $MFT
2696  Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeData, L"", 0, &MftDataContext, NULL);
2697  if (!NT_SUCCESS(Status))
2698  {
2699  DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
2700  ReleaseAttributeContext(MirrDataContext);
2701  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2702  return Status;
2703  }
2704 
2705  // Get the size of the mirror's $DATA attribute
2706  DataLength = AttributeDataLength(MirrDataContext->pRecord);
2707 
2708  ASSERT(DataLength % Vcb->NtfsInfo.BytesPerFileRecord == 0);
2709 
2710  // Create buffer for the mirror's $DATA attribute
2712  if (!DataBuffer)
2713  {
2714  DPRINT1("Error: Couldn't allocate memory for $DATA buffer!\n");
2715  ReleaseAttributeContext(MftDataContext);
2716  ReleaseAttributeContext(MirrDataContext);
2717  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2719  }
2720 
2722 
2723  // Back up the first several entries of the Mft's $DATA Attribute
2724  BytesRead = ReadAttribute(Vcb, MftDataContext, 0, DataBuffer, (ULONG)DataLength);
2725  if (BytesRead != (ULONG)DataLength)
2726  {
2727  DPRINT1("Error: Failed to read $DATA for $MFTMirr!\n");
2728  ReleaseAttributeContext(MftDataContext);
2729  ReleaseAttributeContext(MirrDataContext);
2730  ExFreePoolWithTag(DataBuffer, TAG_NTFS);
2731  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2732  return STATUS_UNSUCCESSFUL;
2733  }
2734 
2735  // Write the mirror's $DATA attribute
2737  MirrDataContext,
2738  0,
2739  (PUCHAR)DataBuffer,
2740  DataLength,
2741  &LengthWritten,
2742  MirrorFileRecord);
2743  if (!NT_SUCCESS(Status))
2744  {
2745  DPRINT1("ERROR: Failed to write $DATA attribute of $MFTMirr!\n");
2746  }
2747 
2748  // Cleanup
2749  ReleaseAttributeContext(MftDataContext);
2750  ReleaseAttributeContext(MirrDataContext);
2751  ExFreePoolWithTag(DataBuffer, TAG_NTFS);
2752  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2753 
2754  return Status;
2755 }
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:1259
#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:1575
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:1009
#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:203
_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 1259 of file mft.c.

1266 {
1267  ULONGLONG LastLCN;
1268  PUCHAR DataRun;
1269  LONGLONG DataRunOffset;
1270  ULONGLONG DataRunLength;
1271  LONGLONG DataRunStartLCN;
1272  ULONGLONG CurrentOffset;
1273  ULONG WriteLength;
1274  NTSTATUS Status;
1275  PUCHAR SourceBuffer = Buffer;
1277  BOOLEAN FileRecordAllocated = FALSE;
1278 
1279  //TEMPTEMP
1280  PUCHAR TempBuffer;
1281 
1282 
1283  DPRINT("WriteAttribute(%p, %p, %I64u, %p, %lu, %p, %p)\n", Vcb, Context, Offset, Buffer, Length, RealLengthWritten, FileRecord);
1284 
1285  *RealLengthWritten = 0;
1286 
1287  // is this a resident attribute?
1288  if (!Context->pRecord->IsNonResident)
1289  {
1290  ULONG AttributeOffset;
1291  PNTFS_ATTR_CONTEXT FoundContext;
1293 
1294  // Ensure requested data is within the bounds of the attribute
1295  ASSERT(Offset + Length <= Context->pRecord->Resident.ValueLength);
1296 
1297  if (Offset + Length > Context->pRecord->Resident.ValueLength)
1298  {
1299  DPRINT1("DRIVER ERROR: Attribute is too small!\n");
1300  return STATUS_INVALID_PARAMETER;
1301  }
1302 
1303  // Do we need to read the file record?
1304  if (FileRecord == NULL)
1305  {
1306  FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
1307  if (!FileRecord)
1308  {
1309  DPRINT1("Error: Couldn't allocate file record!\n");
1310  return STATUS_NO_MEMORY;
1311  }
1312 
1313  FileRecordAllocated = TRUE;
1314 
1315  // read the file record
1316  ReadFileRecord(Vcb, Context->FileMFTIndex, FileRecord);
1317  }
1318 
1319  // find where to write the attribute data to
1320  Status = FindAttribute(Vcb, FileRecord,
1321  Context->pRecord->Type,
1322  (PCWSTR)((ULONG_PTR)Context->pRecord + Context->pRecord->NameOffset),
1323  Context->pRecord->NameLength,
1324  &FoundContext,
1325  &AttributeOffset);
1326 
1327  if (!NT_SUCCESS(Status))
1328  {
1329  DPRINT1("ERROR: Couldn't find matching attribute!\n");
1330  if(FileRecordAllocated)
1331  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
1332  return Status;
1333  }
1334 
1335  Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttributeOffset);
1336 
1337  DPRINT("Offset: %I64u, AttributeOffset: %u, ValueOffset: %u\n", Offset, AttributeOffset, Context->pRecord->Resident.ValueLength);
1338 
1339  // Will we be writing past the end of the allocated file record?
1340  if (Offset + Length + AttributeOffset + Context->pRecord->Resident.ValueOffset > Vcb->NtfsInfo.BytesPerFileRecord)
1341  {
1342  DPRINT1("DRIVER ERROR: Data being written extends past end of file record!\n");
1343  ReleaseAttributeContext(FoundContext);
1344  if (FileRecordAllocated)
1345  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
1346  return STATUS_INVALID_PARAMETER;
1347  }
1348 
1349  // copy the data being written into the file record. We cast Offset to ULONG, which is safe because it's range has been verified.
1350  RtlCopyMemory((PCHAR)((ULONG_PTR)Destination + Context->pRecord->Resident.ValueOffset + (ULONG)Offset), Buffer, Length);
1351 
1352  Status = UpdateFileRecord(Vcb, Context->FileMFTIndex, FileRecord);
1353 
1354  // Update the context's copy of the resident attribute
1355  ASSERT(Context->pRecord->Length == Destination->Length);
1356  RtlCopyMemory((PVOID)Context->pRecord, Destination, Context->pRecord->Length);
1357 
1358  ReleaseAttributeContext(FoundContext);
1359  if (FileRecordAllocated)
1360  ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
1361 
1362  if (NT_SUCCESS(Status))
1363  *RealLengthWritten = Length;
1364 
1365  return Status;
1366  }
1367 
1368  // This is a non-resident attribute.
1369 
1370  // I. Find the corresponding start data run.
1371 
1372  // FIXME: Cache seems to be non-working. Disable it for now
1373  //if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * Volume->ClusterSize)
1374  /*if (0)
1375  {
1376  DataRun = Context->CacheRun;
1377  LastLCN = Context->CacheRunLastLCN;
1378  DataRunStartLCN = Context->CacheRunStartLCN;
1379  DataRunLength = Context->CacheRunLength;
1380  CurrentOffset = Context->CacheRunCurrentOffset;
1381  }
1382  else*/
1383  {
1384  ULONG UsedBufferSize;
1385  LastLCN = 0;
1386  CurrentOffset = 0;
1387 
1388  // This will be rewritten in the next iteration to just use the DataRuns MCB directly
1389  TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
1390  if (TempBuffer == NULL)
1391  {
1393  }
1394 
1395  ConvertLargeMCBToDataRuns(&Context->DataRunsMCB,
1396  TempBuffer,
1397  Vcb->NtfsInfo.BytesPerFileRecord,
1398  &UsedBufferSize);
1399 
1400  DataRun = TempBuffer;
1401 
1402  while (1)
1403  {
1404  DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1405  if (DataRunOffset != -1)
1406  {
1407  // Normal data run.
1408  // DPRINT1("Writing to normal data run, LastLCN %I64u DataRunOffset %I64d\n", LastLCN, DataRunOffset);
1409  DataRunStartLCN = LastLCN + DataRunOffset;
1410  LastLCN = DataRunStartLCN;
1411  }
1412  else
1413  {
1414  // Sparse data run. We can't support writing to sparse files yet
1415  // (it may require increasing the allocation size).
1416  DataRunStartLCN = -1;
1417  DPRINT1("FIXME: Writing to sparse files is not supported yet!\n");
1419  goto Cleanup;
1420  }
1421 
1422  // Have we reached the data run we're trying to write to?
1423  if (Offset >= CurrentOffset &&
1424  Offset < CurrentOffset + (DataRunLength * Vcb->NtfsInfo.BytesPerCluster))
1425  {
1426  break;
1427  }
1428 
1429  if (*DataRun == 0)
1430  {
1431  // We reached the last assigned cluster
1432  // TODO: assign new clusters to the end of the file.
1433  // (Presently, this code will rarely be reached, the write will usually have already failed by now)
1434  // [We can reach here by creating a new file record when the MFT isn't large enough]
1435  DPRINT1("FIXME: Master File Table needs to be enlarged.\n");
1437  goto Cleanup;
1438  }
1439 
1440  CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1441  }
1442  }
1443 
1444  // II. Go through the run list and write the data
1445 
1446  /* REVIEWME -- As adapted from NtfsReadAttribute():
1447  We seem to be making a special case for the first applicable data run, but I'm not sure why.
1448  Does it have something to do with (not) caching? Is this strategy equally applicable to writing? */
1449 
1450  WriteLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset), Length);
1451 
1452  StartingOffset = DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster + Offset - CurrentOffset;
1453 
1454  // Write the data to the disk
1455  Status = NtfsWriteDisk(Vcb->StorageDevice,
1457  WriteLength,
1458  Vcb->NtfsInfo.BytesPerSector,
1459  (PVOID)SourceBuffer);
1460 
1461  // Did the write fail?
1462  if (!NT_SUCCESS(Status))
1463  {
1464  Context->CacheRun = DataRun;
1465  Context->CacheRunOffset = Offset;
1466  Context->CacheRunStartLCN = DataRunStartLCN;
1467  Context->CacheRunLength = DataRunLength;
1468  Context->CacheRunLastLCN = LastLCN;
1469  Context->CacheRunCurrentOffset = CurrentOffset;
1470 
1471  goto Cleanup;
1472  }
1473 
1474  Length -= WriteLength;
1475  SourceBuffer += WriteLength;
1476  *RealLengthWritten += WriteLength;
1477 
1478  // Did we write to the end of the data run?
1479  if (WriteLength == DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset))
1480  {
1481  // Advance to the next data run
1482  CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1483  DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1484 
1485  if (DataRunOffset != (ULONGLONG)-1)
1486  {
1487  DataRunStartLCN = LastLCN + DataRunOffset;
1488  LastLCN = DataRunStartLCN;
1489  }
1490  else
1491  DataRunStartLCN = -1;
1492  }
1493 
1494  // Do we have more data to write?
1495  while (Length > 0)
1496  {
1497  // Make sure we don't write past the end of the current data run
1498  WriteLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster, Length);
1499 
1500  // Are we dealing with a sparse data run?
1501  if (DataRunStartLCN == -1)
1502  {
1503  DPRINT1("FIXME: Don't know how to write to sparse files yet! (DataRunStartLCN == -1)\n");
1505  goto Cleanup;
1506  }
1507  else
1508  {
1509  // write the data to the disk
1510  Status = NtfsWriteDisk(Vcb->StorageDevice,
1511  DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster,
1512  WriteLength,
1513  Vcb->NtfsInfo.BytesPerSector,
1514  (PVOID)SourceBuffer);
1515  if (!NT_SUCCESS(Status))
1516  break;
1517  }
1518 
1519  Leng