mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 17:56:00 +00:00
[NTFS]
When writing to a file, increase the file size if trying to write past the end. *FindAttribute() has been given an optional pointer to a ULONG that will receive the offset of the found attribute from the beginning of the record. This is to allow for found attributes to be written back into their file records. +SetAttributeDataLength() +UpdateFileRecord() - Updates a file record in the master file table at a given index. +AddFixupArray() - Prepares a file record or directory index for writing to the disk. svn path=/branches/GSoC_2016/NTFS/; revision=71660
This commit is contained in:
parent
ea6b9622c4
commit
ba33b9faac
8 changed files with 226 additions and 29 deletions
|
@ -150,6 +150,8 @@ static
|
||||||
PNTFS_ATTR_RECORD
|
PNTFS_ATTR_RECORD
|
||||||
InternalGetNextAttribute(PFIND_ATTR_CONTXT Context)
|
InternalGetNextAttribute(PFIND_ATTR_CONTXT Context)
|
||||||
{
|
{
|
||||||
|
PNTFS_ATTR_RECORD NextAttribute;
|
||||||
|
|
||||||
if (Context->CurrAttr == (PVOID)-1)
|
if (Context->CurrAttr == (PVOID)-1)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -165,7 +167,10 @@ InternalGetNextAttribute(PFIND_ATTR_CONTXT Context)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context->CurrAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
|
NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
|
||||||
|
Context->Offset += ((ULONG_PTR)NextAttribute - (ULONG_PTR)Context->CurrAttr);
|
||||||
|
Context->CurrAttr = NextAttribute;
|
||||||
|
|
||||||
if (Context->CurrAttr < Context->LastAttr &&
|
if (Context->CurrAttr < Context->LastAttr &&
|
||||||
Context->CurrAttr->Type != AttributeEnd)
|
Context->CurrAttr->Type != AttributeEnd)
|
||||||
{
|
{
|
||||||
|
@ -186,7 +191,9 @@ InternalGetNextAttribute(PFIND_ATTR_CONTXT Context)
|
||||||
}
|
}
|
||||||
else if (Context->CurrAttr->Length != 0)
|
else if (Context->CurrAttr->Length != 0)
|
||||||
{
|
{
|
||||||
Context->CurrAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
|
NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
|
||||||
|
Context->Offset += ((ULONG_PTR)NextAttribute - (ULONG_PTR)Context->CurrAttr);
|
||||||
|
Context->CurrAttr = NextAttribute;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -223,6 +230,7 @@ FindFirstAttribute(PFIND_ATTR_CONTXT Context,
|
||||||
Context->LastAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse);
|
Context->LastAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse);
|
||||||
Context->NonResidentStart = NULL;
|
Context->NonResidentStart = NULL;
|
||||||
Context->NonResidentEnd = NULL;
|
Context->NonResidentEnd = NULL;
|
||||||
|
Context->Offset = FileRecord->AttributeOffset;
|
||||||
|
|
||||||
if (Context->FirstAttr->Type == AttributeEnd)
|
if (Context->FirstAttr->Type == AttributeEnd)
|
||||||
{
|
{
|
||||||
|
@ -246,6 +254,7 @@ FindFirstAttribute(PFIND_ATTR_CONTXT Context,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*Attribute = Context->CurrAttr;
|
*Attribute = Context->CurrAttr;
|
||||||
|
Context->Offset = (UCHAR*)Context->CurrAttr - (UCHAR*)FileRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
@ -307,7 +316,8 @@ NtfsDumpFileNameAttribute(PNTFS_ATTR_RECORD Attribute)
|
||||||
|
|
||||||
FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
|
FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
|
||||||
DbgPrint(" (%x) '%.*S' ", FileNameAttr->NameType, FileNameAttr->NameLength, FileNameAttr->Name);
|
DbgPrint(" (%x) '%.*S' ", FileNameAttr->NameType, FileNameAttr->NameLength, FileNameAttr->Name);
|
||||||
DbgPrint(" '%x' ", FileNameAttr->FileAttributes);
|
DbgPrint(" '%x' \n", FileNameAttr->FileAttributes);
|
||||||
|
DbgPrint(" AllocatedSize: %I64u\nDataSize: %I64u\n", FileNameAttr->AllocatedSize, FileNameAttr->DataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -481,8 +491,8 @@ NtfsDumpAttribute(PDEVICE_EXTENSION Vcb,
|
||||||
{
|
{
|
||||||
FindRun(Attribute,0,&lcn, &runcount);
|
FindRun(Attribute,0,&lcn, &runcount);
|
||||||
|
|
||||||
DbgPrint(" AllocatedSize %I64u DataSize %I64u\n",
|
DbgPrint(" AllocatedSize %I64u DataSize %I64u InitilizedSize %I64u\n",
|
||||||
Attribute->NonResident.AllocatedSize, Attribute->NonResident.DataSize);
|
Attribute->NonResident.AllocatedSize, Attribute->NonResident.DataSize, Attribute->NonResident.InitializedSize);
|
||||||
DbgPrint(" logical clusters: %I64u - %I64u\n",
|
DbgPrint(" logical clusters: %I64u - %I64u\n",
|
||||||
lcn, lcn + runcount - 1);
|
lcn, lcn + runcount - 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt,
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PNTFS_ATTR_CONTEXT DataContext;
|
PNTFS_ATTR_CONTEXT DataContext;
|
||||||
|
|
||||||
Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Stream, StreamLength, &DataContext);
|
Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Stream, StreamLength, &DataContext, NULL);
|
||||||
if (NT_SUCCESS(Status))
|
if (NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
Size = AttributeDataLength(&DataContext->Record);
|
Size = AttributeDataLength(&DataContext->Record);
|
||||||
|
|
|
@ -568,7 +568,7 @@ NtfsDirFindFile(PNTFS_VCB Vcb,
|
||||||
}
|
}
|
||||||
else if (Colon != 0)
|
else if (Colon != 0)
|
||||||
{
|
{
|
||||||
Status = FindAttribute(Vcb, FileRecord, AttributeData, Colon, wcslen(Colon), &DataContext);
|
Status = FindAttribute(Vcb, FileRecord, AttributeData, Colon, wcslen(Colon), &DataContext, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
@ -741,7 +741,7 @@ NtfsReadFCBAttribute(PNTFS_VCB Vcb,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt);
|
Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ExFreePoolWithTag(FileRecord, TAG_NTFS);
|
ExFreePoolWithTag(FileRecord, TAG_NTFS);
|
||||||
|
|
|
@ -295,7 +295,7 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeData, L"", 0, &DeviceExt->MFTContext);
|
Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeData, L"", 0, &DeviceExt->MFTContext, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("Can't find data attribute for Master File Table.\n");
|
DPRINT1("Can't find data attribute for Master File Table.\n");
|
||||||
|
@ -333,7 +333,7 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
|
||||||
NtfsDumpFileAttributes(DeviceExt, VolumeRecord);
|
NtfsDumpFileAttributes(DeviceExt, VolumeRecord);
|
||||||
|
|
||||||
/* Get volume name */
|
/* Get volume name */
|
||||||
Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeName, L"", 0, &AttrCtxt);
|
Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeName, L"", 0, &AttrCtxt, NULL);
|
||||||
|
|
||||||
if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0)
|
if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0)
|
||||||
{
|
{
|
||||||
|
@ -374,7 +374,7 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
|
||||||
DeviceExt->VolumeFcb = VolumeFcb;
|
DeviceExt->VolumeFcb = VolumeFcb;
|
||||||
|
|
||||||
/* Get volume information */
|
/* Get volume information */
|
||||||
Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeInformation, L"", 0, &AttrCtxt);
|
Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeInformation, L"", 0, &AttrCtxt, NULL);
|
||||||
|
|
||||||
if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0)
|
if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0)
|
||||||
{
|
{
|
||||||
|
@ -804,7 +804,7 @@ GetVolumeBitmap(PDEVICE_EXTENSION DeviceExt,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext);
|
Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("Failed find $DATA for bitmap: %lx\n", Status);
|
DPRINT1("Failed find $DATA for bitmap: %lx\n", Status);
|
||||||
|
|
|
@ -81,13 +81,24 @@ ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name FindAttribute
|
||||||
|
* @implemented
|
||||||
|
*
|
||||||
|
* Searches a file record for an attribute matching the given type and name.
|
||||||
|
*
|
||||||
|
* @param Offset
|
||||||
|
* Optional 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
|
NTSTATUS
|
||||||
FindAttribute(PDEVICE_EXTENSION Vcb,
|
FindAttribute(PDEVICE_EXTENSION Vcb,
|
||||||
PFILE_RECORD_HEADER MftRecord,
|
PFILE_RECORD_HEADER MftRecord,
|
||||||
ULONG Type,
|
ULONG Type,
|
||||||
PCWSTR Name,
|
PCWSTR Name,
|
||||||
ULONG NameLength,
|
ULONG NameLength,
|
||||||
PNTFS_ATTR_CONTEXT * AttrCtx)
|
PNTFS_ATTR_CONTEXT * AttrCtx,
|
||||||
|
PULONG Offset)
|
||||||
{
|
{
|
||||||
BOOLEAN Found;
|
BOOLEAN Found;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
@ -123,6 +134,10 @@ FindAttribute(PDEVICE_EXTENSION Vcb,
|
||||||
/* Found it, fill up the context and return. */
|
/* Found it, fill up the context and return. */
|
||||||
DPRINT("Found context\n");
|
DPRINT("Found context\n");
|
||||||
*AttrCtx = PrepareAttributeContext(Attribute);
|
*AttrCtx = PrepareAttributeContext(Attribute);
|
||||||
|
|
||||||
|
if (Offset != NULL)
|
||||||
|
*Offset = Context.Offset;
|
||||||
|
|
||||||
FindCloseAttribute(&Context);
|
FindCloseAttribute(&Context);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -156,6 +171,61 @@ AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
SetAttributeDataLength(PFILE_OBJECT FileObject,
|
||||||
|
PNTFS_FCB Fcb,
|
||||||
|
PNTFS_ATTR_CONTEXT AttrContext,
|
||||||
|
ULONG AttrOffset,
|
||||||
|
PFILE_RECORD_HEADER FileRecord,
|
||||||
|
PDEVICE_EXTENSION DeviceExt,
|
||||||
|
PLARGE_INTEGER DataSize)
|
||||||
|
{
|
||||||
|
if (AttrContext->Record.IsNonResident)
|
||||||
|
{
|
||||||
|
// do we need to increase the allocation size?
|
||||||
|
if (AttrContext->Record.NonResident.AllocatedSize < DataSize->QuadPart)
|
||||||
|
{
|
||||||
|
DPRINT1("FixMe: Increasing allocation size is unimplemented!\n");
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: is the file compressed, encrypted, or sparse?
|
||||||
|
|
||||||
|
// NOTE: we need to have acquired the main resource exclusively, as well as(?) the PagingIoResource
|
||||||
|
|
||||||
|
// TODO: update the allocated size on-disk
|
||||||
|
DPRINT("Allocated Size: %I64u\n", AttrContext->Record.NonResident.AllocatedSize);
|
||||||
|
|
||||||
|
AttrContext->Record.NonResident.DataSize = DataSize->QuadPart;
|
||||||
|
AttrContext->Record.NonResident.InitializedSize = DataSize->QuadPart;
|
||||||
|
|
||||||
|
Fcb->RFCB.FileSize = *DataSize;
|
||||||
|
Fcb->RFCB.ValidDataLength = *DataSize;
|
||||||
|
|
||||||
|
DPRINT("Data Size: %I64u\n", Fcb->RFCB.FileSize.QuadPart);
|
||||||
|
|
||||||
|
//NtfsDumpFileAttributes(Fcb->Vcb, FileRecord);
|
||||||
|
|
||||||
|
// copy the attribute back into the FileRecord
|
||||||
|
RtlCopyMemory((PCHAR)FileRecord + AttrOffset, &AttrContext->Record, AttrContext->Record.Length);
|
||||||
|
|
||||||
|
//NtfsDumpFileAttributes(Fcb->Vcb, FileRecord);
|
||||||
|
|
||||||
|
// write the updated file record back to disk
|
||||||
|
UpdateFileRecord(Fcb->Vcb, Fcb->MFTIndex, FileRecord);
|
||||||
|
|
||||||
|
CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we can't yet handle resident attributes
|
||||||
|
DPRINT1("FixMe: Can't handle increasing length of resident attribute\n");
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
ULONG
|
ULONG
|
||||||
ReadAttribute(PDEVICE_EXTENSION Vcb,
|
ReadAttribute(PDEVICE_EXTENSION Vcb,
|
||||||
PNTFS_ATTR_CONTEXT Context,
|
PNTFS_ATTR_CONTEXT Context,
|
||||||
|
@ -612,6 +682,37 @@ ReadFileRecord(PDEVICE_EXTENSION Vcb,
|
||||||
return FixupUpdateSequenceArray(Vcb, &file->Ntfs);
|
return FixupUpdateSequenceArray(Vcb, &file->Ntfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UpdateFileRecord
|
||||||
|
* @implemented
|
||||||
|
* Writes a file record to the master file table, at a given index.
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
UpdateFileRecord(PDEVICE_EXTENSION Vcb,
|
||||||
|
ULONGLONG index,
|
||||||
|
PFILE_RECORD_HEADER file)
|
||||||
|
{
|
||||||
|
ULONG BytesWritten;
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
DPRINT("UpdateFileRecord(%p, %I64x, %p)\n", Vcb, index, file);
|
||||||
|
|
||||||
|
// Add the fixup array to prepare the data for writing to disk
|
||||||
|
AddFixupArray(Vcb, file);
|
||||||
|
|
||||||
|
// write the file record to the master file table
|
||||||
|
Status = WriteAttribute(Vcb, Vcb->MFTContext, index * Vcb->NtfsInfo.BytesPerFileRecord, (const PUCHAR)file, Vcb->NtfsInfo.BytesPerFileRecord, &BytesWritten);
|
||||||
|
|
||||||
|
// TODO: Update MFT mirror
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("UpdateFileRecord failed: %I64u written, %u expected\n", BytesWritten, Vcb->NtfsInfo.BytesPerFileRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
|
FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
|
||||||
|
@ -627,6 +728,8 @@ FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
|
||||||
USACount = Record->UsaCount - 1; /* Exclude the USA Number. */
|
USACount = Record->UsaCount - 1; /* Exclude the USA Number. */
|
||||||
Block = (USHORT*)((PCHAR)Record + Vcb->NtfsInfo.BytesPerSector - 2);
|
Block = (USHORT*)((PCHAR)Record + Vcb->NtfsInfo.BytesPerSector - 2);
|
||||||
|
|
||||||
|
DPRINT("FixupUpdateSequenceArray(%p, %p)\nUSANumber: %u\tUSACount: %u\n", Vcb, Record, USANumber, USACount);
|
||||||
|
|
||||||
while (USACount)
|
while (USACount)
|
||||||
{
|
{
|
||||||
if (*Block != USANumber)
|
if (*Block != USANumber)
|
||||||
|
@ -642,6 +745,36 @@ FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
AddFixupArray(PDEVICE_EXTENSION Vcb,
|
||||||
|
PFILE_RECORD_HEADER Record)
|
||||||
|
{
|
||||||
|
USHORT *pShortToFixUp;
|
||||||
|
unsigned int ArrayEntryCount = Record->BytesAllocated / Vcb->NtfsInfo.BytesPerSector;
|
||||||
|
unsigned int Offset = Vcb->NtfsInfo.BytesPerSector - 2;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
PFIXUP_ARRAY fixupArray = (PFIXUP_ARRAY)((UCHAR*)Record + Record->Ntfs.UsaOffset);
|
||||||
|
|
||||||
|
DPRINT("AddFixupArray(%p, %p)\n fixupArray->USN: %u, ArrayEntryCount: %u\n", Vcb, Record, fixupArray->USN, ArrayEntryCount);
|
||||||
|
|
||||||
|
if (Record->BytesAllocated % Vcb->NtfsInfo.BytesPerSector != 0)
|
||||||
|
ArrayEntryCount++;
|
||||||
|
|
||||||
|
fixupArray->USN++;
|
||||||
|
|
||||||
|
for (i = 0; i < ArrayEntryCount; i++)
|
||||||
|
{
|
||||||
|
DPRINT("USN: %u\tOffset: %u\n", fixupArray->USN, Offset);
|
||||||
|
|
||||||
|
pShortToFixUp = (USHORT*)((UCHAR*)Record + Offset);
|
||||||
|
fixupArray->Array[i] = *pShortToFixUp;
|
||||||
|
*pShortToFixUp = fixupArray->USN;
|
||||||
|
Offset += Vcb->NtfsInfo.BytesPerSector;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
ReadLCN(PDEVICE_EXTENSION Vcb,
|
ReadLCN(PDEVICE_EXTENSION Vcb,
|
||||||
|
@ -780,7 +913,7 @@ BrowseIndexEntries(PDEVICE_EXTENSION Vcb,
|
||||||
return STATUS_OBJECT_PATH_NOT_FOUND;
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationCtx);
|
Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationCtx, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT("Corrupted filesystem!\n");
|
DPRINT("Corrupted filesystem!\n");
|
||||||
|
@ -850,7 +983,7 @@ NtfsFindMftRecord(PDEVICE_EXTENSION Vcb,
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
|
ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
|
||||||
Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx);
|
Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ExFreePoolWithTag(MftRecord, TAG_NTFS);
|
ExFreePoolWithTag(MftRecord, TAG_NTFS);
|
||||||
|
|
|
@ -483,8 +483,15 @@ typedef struct _FIND_ATTR_CONTXT
|
||||||
PNTFS_ATTR_RECORD LastAttr;
|
PNTFS_ATTR_RECORD LastAttr;
|
||||||
PNTFS_ATTR_RECORD NonResidentStart;
|
PNTFS_ATTR_RECORD NonResidentStart;
|
||||||
PNTFS_ATTR_RECORD NonResidentEnd;
|
PNTFS_ATTR_RECORD NonResidentEnd;
|
||||||
|
ULONG Offset;
|
||||||
} FIND_ATTR_CONTXT, *PFIND_ATTR_CONTXT;
|
} FIND_ATTR_CONTXT, *PFIND_ATTR_CONTXT;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
USHORT USN;
|
||||||
|
USHORT Array[];
|
||||||
|
} FIXUP_ARRAY, *PFIXUP_ARRAY;
|
||||||
|
|
||||||
extern PNTFS_GLOBAL_DATA NtfsGlobalData;
|
extern PNTFS_GLOBAL_DATA NtfsGlobalData;
|
||||||
|
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
|
@ -555,7 +562,7 @@ NtfsWriteDisk(IN PDEVICE_OBJECT DeviceObject,
|
||||||
IN LONGLONG StartingOffset,
|
IN LONGLONG StartingOffset,
|
||||||
IN ULONG Length,
|
IN ULONG Length,
|
||||||
IN ULONG SectorSize,
|
IN ULONG SectorSize,
|
||||||
IN PUCHAR Buffer);
|
IN const PUCHAR Buffer);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject,
|
NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
@ -759,6 +766,15 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
|
||||||
ULONGLONG
|
ULONGLONG
|
||||||
AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord);
|
AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
SetAttributeDataLength(PFILE_OBJECT FileObject,
|
||||||
|
PNTFS_FCB Fcb,
|
||||||
|
PNTFS_ATTR_CONTEXT AttrContext,
|
||||||
|
ULONG AttrOffset,
|
||||||
|
PFILE_RECORD_HEADER FileRecord,
|
||||||
|
PDEVICE_EXTENSION DeviceExt,
|
||||||
|
PLARGE_INTEGER DataSize);
|
||||||
|
|
||||||
ULONG
|
ULONG
|
||||||
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord);
|
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord);
|
||||||
|
|
||||||
|
@ -767,13 +783,19 @@ ReadFileRecord(PDEVICE_EXTENSION Vcb,
|
||||||
ULONGLONG index,
|
ULONGLONG index,
|
||||||
PFILE_RECORD_HEADER file);
|
PFILE_RECORD_HEADER file);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
UpdateFileRecord(PDEVICE_EXTENSION Vcb,
|
||||||
|
ULONGLONG index,
|
||||||
|
PFILE_RECORD_HEADER file);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
FindAttribute(PDEVICE_EXTENSION Vcb,
|
FindAttribute(PDEVICE_EXTENSION Vcb,
|
||||||
PFILE_RECORD_HEADER MftRecord,
|
PFILE_RECORD_HEADER MftRecord,
|
||||||
ULONG Type,
|
ULONG Type,
|
||||||
PCWSTR Name,
|
PCWSTR Name,
|
||||||
ULONG NameLength,
|
ULONG NameLength,
|
||||||
PNTFS_ATTR_CONTEXT * AttrCtx);
|
PNTFS_ATTR_CONTEXT * AttrCtx,
|
||||||
|
PULONG Offset);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
ReadVCN(PDEVICE_EXTENSION Vcb,
|
ReadVCN(PDEVICE_EXTENSION Vcb,
|
||||||
|
@ -787,6 +809,10 @@ NTSTATUS
|
||||||
FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
|
FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
|
||||||
PNTFS_RECORD_HEADER Record);
|
PNTFS_RECORD_HEADER Record);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
AddFixupArray(PDEVICE_EXTENSION Vcb,
|
||||||
|
PFILE_RECORD_HEADER Record);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
ReadLCN(PDEVICE_EXTENSION Vcb,
|
ReadLCN(PDEVICE_EXTENSION Vcb,
|
||||||
ULONGLONG lcn,
|
ULONGLONG lcn,
|
||||||
|
|
|
@ -95,7 +95,7 @@ NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext);
|
Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
NTSTATUS BrowseStatus;
|
NTSTATUS BrowseStatus;
|
||||||
|
@ -309,6 +309,7 @@ NTSTATUS NtfsWriteFile(PDEVICE_EXTENSION DeviceExt,
|
||||||
PNTFS_FCB Fcb;
|
PNTFS_FCB Fcb;
|
||||||
PFILE_RECORD_HEADER FileRecord;
|
PFILE_RECORD_HEADER FileRecord;
|
||||||
PNTFS_ATTR_CONTEXT DataContext;
|
PNTFS_ATTR_CONTEXT DataContext;
|
||||||
|
ULONG AttributeOffset;
|
||||||
ULONGLONG StreamSize;
|
ULONGLONG StreamSize;
|
||||||
|
|
||||||
DPRINT("NtfsWriteFile(%p, %p, %p, %u, %u, %x, %p)\n", DeviceExt, FileObject, Buffer, Length, WriteOffset, IrpFlags, LengthWritten);
|
DPRINT("NtfsWriteFile(%p, %p, %p, %u, %u, %x, %p)\n", DeviceExt, FileObject, Buffer, Length, WriteOffset, IrpFlags, LengthWritten);
|
||||||
|
@ -361,9 +362,10 @@ NTSTATUS NtfsWriteFile(PDEVICE_EXTENSION DeviceExt,
|
||||||
|
|
||||||
DPRINT("Found record for %wS\n", Fcb->ObjectName);
|
DPRINT("Found record for %wS\n", Fcb->ObjectName);
|
||||||
|
|
||||||
// Find the attribute (in the NTFS sense of the word) with the data stream for our file
|
// Find the attribute with the data stream for our file
|
||||||
DPRINT("Finding Data Attribute...\n");
|
DPRINT("Finding Data Attribute...\n");
|
||||||
Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext);
|
Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext,
|
||||||
|
&AttributeOffset);
|
||||||
|
|
||||||
// Did we fail to find the attribute?
|
// Did we fail to find the attribute?
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
|
@ -405,13 +407,39 @@ NTSTATUS NtfsWriteFile(PDEVICE_EXTENSION DeviceExt,
|
||||||
// Are we trying to write beyond the end of the stream?
|
// Are we trying to write beyond the end of the stream?
|
||||||
if (WriteOffset + Length > StreamSize)
|
if (WriteOffset + Length > StreamSize)
|
||||||
{
|
{
|
||||||
// TODO: allocate additional clusters as needed and expand stream
|
// is increasing the stream size allowed?
|
||||||
DPRINT1("WriteOffset: %lu\tLength: %lu\tStreamSize: %I64u\n", WriteOffset, Length, StreamSize);
|
if (!(Fcb->Flags & FCB_IS_VOLUME) &&
|
||||||
DPRINT1("TODO: Stream embiggening (appending files) is not yet supported!\n");
|
!(IrpFlags & IRP_PAGING_IO))
|
||||||
|
{
|
||||||
|
LARGE_INTEGER DataSize;
|
||||||
|
ULONGLONG AllocationSize;
|
||||||
|
|
||||||
|
DataSize.QuadPart = WriteOffset + Length;
|
||||||
|
|
||||||
|
AllocationSize = ROUND_UP(DataSize.QuadPart, Fcb->Vcb->NtfsInfo.BytesPerCluster);
|
||||||
|
|
||||||
|
// set the attribute data length
|
||||||
|
Status = SetAttributeDataLength(FileObject, Fcb, DataContext, AttributeOffset, FileRecord, DeviceExt, &DataSize);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
ReleaseAttributeContext(DataContext);
|
ReleaseAttributeContext(DataContext);
|
||||||
ExFreePoolWithTag(FileRecord, TAG_NTFS);
|
ExFreePoolWithTag(FileRecord, TAG_NTFS);
|
||||||
*LengthWritten = 0; // We didn't write anything
|
*LengthWritten = 0;
|
||||||
return STATUS_ACCESS_DENIED; // temporarily; we don't change file sizes yet
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we need to update this file's size in every directory index entry that references it
|
||||||
|
// (saved for a later commit)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO - just fail for now
|
||||||
|
ReleaseAttributeContext(DataContext);
|
||||||
|
ExFreePoolWithTag(FileRecord, TAG_NTFS);
|
||||||
|
*LengthWritten = 0;
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT("Length: %lu\tWriteOffset: %lu\tStreamSize: %I64u\n", Length, WriteOffset, StreamSize);
|
DPRINT("Length: %lu\tWriteOffset: %lu\tStreamSize: %I64u\n", Length, WriteOffset, StreamSize);
|
||||||
|
|
|
@ -62,7 +62,7 @@ NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext);
|
Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
|
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue