mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 21:23:05 +00:00
[NTFS] - Fix increasing the mft size, to keep chkdsk happy.
IncreaseMftSize() - Add some fixes. Write blank records to newly-allocated mft entries, and update $MFTMirr when finished; these changes are needed for chkdsk. Increase size by 64 records instead of 8. +UpdateMftMirror() - Backs up the first ~4 master file table entries to the $MFTMirr file. svn path=/branches/GSoC_2016/NTFS/; revision=75694
This commit is contained in:
parent
9a91a51f17
commit
5e7c11842a
2 changed files with 195 additions and 8 deletions
|
@ -30,6 +30,7 @@
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES *****************************************************************/
|
||||||
|
|
||||||
#include "ntfs.h"
|
#include "ntfs.h"
|
||||||
|
#include <ntintsafe.h>
|
||||||
|
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
@ -228,7 +229,7 @@ AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
|
||||||
* STATUS_CANT_WAIT if CanWait was FALSE and the function could not get immediate, exclusive access to the MFT.
|
* STATUS_CANT_WAIT if CanWait was FALSE and the function could not get immediate, exclusive access to the MFT.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* Increases the size of the Master File Table by 8 records. Bitmap entries for the new records are cleared,
|
* 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.
|
* 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.
|
* This function will wait for exlusive access to the volume fcb.
|
||||||
*/
|
*/
|
||||||
|
@ -239,13 +240,17 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
LARGE_INTEGER BitmapSize;
|
LARGE_INTEGER BitmapSize;
|
||||||
LARGE_INTEGER DataSize;
|
LARGE_INTEGER DataSize;
|
||||||
LONGLONG BitmapSizeDifference;
|
LONGLONG BitmapSizeDifference;
|
||||||
ULONG DataSizeDifference = Vcb->NtfsInfo.BytesPerFileRecord * 8;
|
ULONG NewRecords = ATTR_RECORD_ALIGNMENT * 8; // Allocate one new record for every bit of every byte we'll be adding to the bitmap
|
||||||
|
ULONG DataSizeDifference = Vcb->NtfsInfo.BytesPerFileRecord * NewRecords;
|
||||||
ULONG BitmapOffset;
|
ULONG BitmapOffset;
|
||||||
PUCHAR BitmapBuffer;
|
PUCHAR BitmapBuffer;
|
||||||
ULONGLONG BitmapBytes;
|
ULONGLONG BitmapBytes;
|
||||||
ULONGLONG NewBitmapSize;
|
ULONGLONG NewBitmapSize;
|
||||||
|
ULONGLONG FirstNewMftIndex;
|
||||||
ULONG BytesRead;
|
ULONG BytesRead;
|
||||||
ULONG LengthWritten;
|
ULONG LengthWritten;
|
||||||
|
PFILE_RECORD_HEADER BlankFileRecord;
|
||||||
|
ULONG i;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
DPRINT1("IncreaseMftSize(%p, %s)\n", Vcb, CanWait ? "TRUE" : "FALSE");
|
DPRINT1("IncreaseMftSize(%p, %s)\n", Vcb, CanWait ? "TRUE" : "FALSE");
|
||||||
|
@ -256,11 +261,23 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
return STATUS_CANT_WAIT;
|
return STATUS_CANT_WAIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a blank file record that will be used later
|
||||||
|
BlankFileRecord = NtfsCreateEmptyFileRecord(Vcb);
|
||||||
|
if (!BlankFileRecord)
|
||||||
|
{
|
||||||
|
DPRINT1("Error: Unable to create empty file record!\n");
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the flags (file record is not in use)
|
||||||
|
BlankFileRecord->Flags = 0;
|
||||||
|
|
||||||
// Find the bitmap attribute of master file table
|
// Find the bitmap attribute of master file table
|
||||||
Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, &BitmapOffset);
|
Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
|
DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
ExReleaseResourceLite(&(Vcb->DirResource));
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -271,8 +288,16 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
// Calculate the new mft size
|
// Calculate the new mft size
|
||||||
DataSize.QuadPart = AttributeDataLength(Vcb->MFTContext->pRecord) + DataSizeDifference;
|
DataSize.QuadPart = AttributeDataLength(Vcb->MFTContext->pRecord) + DataSizeDifference;
|
||||||
|
|
||||||
|
// Find the index of the first Mft entry that will be created
|
||||||
|
FirstNewMftIndex = AttributeDataLength(Vcb->MFTContext->pRecord) / Vcb->NtfsInfo.BytesPerFileRecord;
|
||||||
|
|
||||||
// Determine how many bytes will make up the bitmap
|
// Determine how many bytes will make up the bitmap
|
||||||
BitmapBytes = DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord / 8;
|
BitmapBytes = DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord / 8;
|
||||||
|
if ((DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord) % 8 != 0)
|
||||||
|
BitmapBytes++;
|
||||||
|
|
||||||
|
// Windows will always keep the number of bytes in a bitmap as a multiple of 8, so no bytes are wasted on slack
|
||||||
|
BitmapBytes = ALIGN_UP_BY(BitmapBytes, ATTR_RECORD_ALIGNMENT);
|
||||||
|
|
||||||
// Determine how much we need to adjust the bitmap size (it's possible we don't)
|
// Determine how much we need to adjust the bitmap size (it's possible we don't)
|
||||||
BitmapSizeDifference = BitmapBytes - BitmapSize.QuadPart;
|
BitmapSizeDifference = BitmapBytes - BitmapSize.QuadPart;
|
||||||
|
@ -283,6 +308,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
if (!BitmapBuffer)
|
if (!BitmapBuffer)
|
||||||
{
|
{
|
||||||
DPRINT1("ERROR: Unable to allocate memory for bitmap attribute!\n");
|
DPRINT1("ERROR: Unable to allocate memory for bitmap attribute!\n");
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
ExReleaseResourceLite(&(Vcb->DirResource));
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
ReleaseAttributeContext(BitmapContext);
|
ReleaseAttributeContext(BitmapContext);
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
@ -300,6 +326,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
if (BytesRead != BitmapSize.LowPart)
|
if (BytesRead != BitmapSize.LowPart)
|
||||||
{
|
{
|
||||||
DPRINT1("ERROR: Bytes read != Bitmap size!\n");
|
DPRINT1("ERROR: Bytes read != Bitmap size!\n");
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
ExReleaseResourceLite(&(Vcb->DirResource));
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
||||||
ReleaseAttributeContext(BitmapContext);
|
ReleaseAttributeContext(BitmapContext);
|
||||||
|
@ -311,17 +338,29 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("ERROR: Failed to set size of $MFT data attribute!\n");
|
DPRINT1("ERROR: Failed to set size of $MFT data attribute!\n");
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
ExReleaseResourceLite(&(Vcb->DirResource));
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
||||||
ReleaseAttributeContext(BitmapContext);
|
ReleaseAttributeContext(BitmapContext);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll need to find the bitmap again, because its offset will have changed after resizing the data attribute
|
||||||
|
ReleaseAttributeContext(BitmapContext);
|
||||||
|
Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, &BitmapOffset);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
// If the bitmap grew
|
// If the bitmap grew
|
||||||
if (BitmapSizeDifference > 0)
|
if (BitmapSizeDifference > 0)
|
||||||
{
|
{
|
||||||
// Set the new bitmap size
|
// Set the new bitmap size
|
||||||
BitmapSize.QuadPart += BitmapSizeDifference;
|
BitmapSize.QuadPart = NewBitmapSize;
|
||||||
if (BitmapContext->pRecord->IsNonResident)
|
if (BitmapContext->pRecord->IsNonResident)
|
||||||
Status = SetNonResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize);
|
Status = SetNonResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize);
|
||||||
else
|
else
|
||||||
|
@ -330,6 +369,7 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("ERROR: Failed to set size of bitmap attribute!\n");
|
DPRINT1("ERROR: Failed to set size of bitmap attribute!\n");
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
ExReleaseResourceLite(&(Vcb->DirResource));
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
||||||
ReleaseAttributeContext(BitmapContext);
|
ReleaseAttributeContext(BitmapContext);
|
||||||
|
@ -337,13 +377,14 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//NtfsDumpFileAttributes(Vcb, FileRecord);
|
NtfsDumpFileAttributes(Vcb, Vcb->MasterFileTable);
|
||||||
|
|
||||||
// Update the file record with the new attribute sizes
|
// Update the file record with the new attribute sizes
|
||||||
Status = UpdateFileRecord(Vcb, Vcb->VolumeFcb->MFTIndex, Vcb->MasterFileTable);
|
Status = UpdateFileRecord(Vcb, Vcb->VolumeFcb->MFTIndex, Vcb->MasterFileTable);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("ERROR: Failed to update $MFT file record!\n");
|
DPRINT1("ERROR: Failed to update $MFT file record!\n");
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
ExReleaseResourceLite(&(Vcb->DirResource));
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
||||||
ReleaseAttributeContext(BitmapContext);
|
ReleaseAttributeContext(BitmapContext);
|
||||||
|
@ -351,9 +392,10 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out the new bitmap
|
// Write out the new bitmap
|
||||||
Status = WriteAttribute(Vcb, BitmapContext, BitmapOffset, BitmapBuffer, BitmapSize.LowPart, &LengthWritten, Vcb->MasterFileTable);
|
Status = WriteAttribute(Vcb, BitmapContext, 0, BitmapBuffer, NewBitmapSize, &LengthWritten, Vcb->MasterFileTable);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
ExReleaseResourceLite(&(Vcb->DirResource));
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
||||||
ReleaseAttributeContext(BitmapContext);
|
ReleaseAttributeContext(BitmapContext);
|
||||||
|
@ -361,12 +403,31 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create blank records for the new file record entries.
|
||||||
|
for (i = 0; i < NewRecords; i++)
|
||||||
|
{
|
||||||
|
Status = UpdateFileRecord(Vcb, FirstNewMftIndex + i, BlankFileRecord);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR: Failed to write blank file record!\n");
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
|
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
||||||
|
ReleaseAttributeContext(BitmapContext);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the mft mirror
|
||||||
|
Status = UpdateMftMirror(Vcb);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
|
ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
|
||||||
ExReleaseResourceLite(&(Vcb->DirResource));
|
ExReleaseResourceLite(&(Vcb->DirResource));
|
||||||
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
|
||||||
ReleaseAttributeContext(BitmapContext);
|
ReleaseAttributeContext(BitmapContext);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2384,6 +2445,129 @@ CompareFileName(PUNICODE_STRING FileName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name UpdateMftMirror
|
||||||
|
* @implemented
|
||||||
|
*
|
||||||
|
* Backs-up the first ~4 master file table entries to the $MFTMirr file.
|
||||||
|
*
|
||||||
|
* @param Vcb
|
||||||
|
* Pointer to an NTFS_VCB for the volume whose Mft mirror is being updated.
|
||||||
|
*
|
||||||
|
* @returninja livecd
|
||||||
|
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
PFILE_RECORD_HEADER MirrorFileRecord;
|
||||||
|
PNTFS_ATTR_CONTEXT MirrDataContext;
|
||||||
|
PNTFS_ATTR_CONTEXT MftDataContext;
|
||||||
|
PCHAR DataBuffer;
|
||||||
|
ULONGLONG DataLength;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG BytesRead;
|
||||||
|
ULONG LengthWritten;
|
||||||
|
|
||||||
|
// Allocate memory for the Mft mirror file record
|
||||||
|
MirrorFileRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
|
||||||
|
if (!MirrorFileRecord)
|
||||||
|
{
|
||||||
|
DPRINT1("Error: Failed to allocate memory for $MFTMirr!\n");
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the Mft Mirror file record
|
||||||
|
Status = ReadFileRecord(Vcb, NTFS_FILE_MFTMIRR, MirrorFileRecord);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR: Failed to read $MFTMirr!\n");
|
||||||
|
ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the $DATA attribute of $MFTMirr
|
||||||
|
Status = FindAttribute(Vcb, MirrorFileRecord, AttributeData, L"", 0, &MirrDataContext, NULL);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
|
||||||
|
ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the $DATA attribute of $MFT
|
||||||
|
Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeData, L"", 0, &MftDataContext, NULL);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
|
||||||
|
ReleaseAttributeContext(MirrDataContext);
|
||||||
|
ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the size of the mirror's $DATA attribute
|
||||||
|
DataLength = AttributeDataLength(MirrDataContext->pRecord);
|
||||||
|
|
||||||
|
ASSERT(DataLength % Vcb->NtfsInfo.BytesPerFileRecord == 0);
|
||||||
|
|
||||||
|
// Create buffer for the mirror's $DATA attribute
|
||||||
|
DataBuffer = ExAllocatePoolWithTag(NonPagedPool, DataLength, TAG_NTFS);
|
||||||
|
if (!DataBuffer)
|
||||||
|
{
|
||||||
|
DPRINT1("Error: Couldn't allocate memory for $DATA buffer!\n");
|
||||||
|
ReleaseAttributeContext(MftDataContext);
|
||||||
|
ReleaseAttributeContext(MirrDataContext);
|
||||||
|
ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(DataLength < ULONG_MAX);
|
||||||
|
|
||||||
|
// Back up the first several entries of the Mft's $DATA Attribute
|
||||||
|
BytesRead = ReadAttribute(Vcb, MftDataContext, 0, DataBuffer, (ULONG)DataLength);
|
||||||
|
if (BytesRead != (ULONG)DataLength)
|
||||||
|
{
|
||||||
|
DPRINT1("Error: Failed to read $DATA for $MFTMirr!\n");
|
||||||
|
ReleaseAttributeContext(MftDataContext);
|
||||||
|
ReleaseAttributeContext(MirrDataContext);
|
||||||
|
ExFreePoolWithTag(DataBuffer, TAG_NTFS);
|
||||||
|
ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the mirror's $DATA attribute
|
||||||
|
Status = WriteAttribute(Vcb,
|
||||||
|
MirrDataContext,
|
||||||
|
0,
|
||||||
|
(PUCHAR)DataBuffer,
|
||||||
|
DataLength,
|
||||||
|
&LengthWritten,
|
||||||
|
MirrorFileRecord);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR: Failed to write $DATA attribute of $MFTMirr!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
ReleaseAttributeContext(MftDataContext);
|
||||||
|
ReleaseAttributeContext(MirrDataContext);
|
||||||
|
ExFreePoolWithTag(DataBuffer, TAG_NTFS);
|
||||||
|
ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static
|
static
|
||||||
VOID
|
VOID
|
||||||
|
|
|
@ -1047,6 +1047,9 @@ CompareFileName(PUNICODE_STRING FileName,
|
||||||
BOOLEAN DirSearch,
|
BOOLEAN DirSearch,
|
||||||
BOOLEAN CaseSensitive);
|
BOOLEAN CaseSensitive);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
UpdateMftMirror(PNTFS_VCB Vcb);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
ReadFileRecord(PDEVICE_EXTENSION Vcb,
|
ReadFileRecord(PDEVICE_EXTENSION Vcb,
|
||||||
ULONGLONG index,
|
ULONGLONG index,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue