* @param Vcb
* Pointer to the VCB (DEVICE_EXTENSION) of the target volume.
*
+*
+* @param CanWait
+* Boolean 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.
+*
* @return
* 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 8 records. Bitmap entries for the new records are cleared,
* This function will wait for exlusive access to the volume fcb.
*/
NTSTATUS
-IncreaseMftSize(PDEVICE_EXTENSION Vcb)
+IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
{
PNTFS_ATTR_CONTEXT BitmapContext;
LARGE_INTEGER BitmapSize;
ULONG LengthWritten;
NTSTATUS Status;
- DPRINT1("IncreaseMftSize(%p)\n", Vcb);
+ DPRINT1("IncreaseMftSize(%p, %s)\n", Vcb, CanWait ? "TRUE" : "FALSE");
// We need exclusive access to the mft while we change its size
- if (!ExAcquireResourceExclusiveLite(&(Vcb->DirResource), TRUE))
+ if (!ExAcquireResourceExclusiveLite(&(Vcb->DirResource), CanWait))
{
return STATUS_CANT_WAIT;
}
PUNICODE_STRING FileName,
BOOLEAN DirSearch,
ULONGLONG NewDataSize,
- ULONGLONG NewAllocationSize)
+ ULONGLONG NewAllocationSize,
+ BOOLEAN CaseSensitive)
{
PFILE_RECORD_HEADER MftRecord;
PNTFS_ATTR_CONTEXT IndexRootCtx;
NTSTATUS Status;
ULONG CurrentEntry = 0;
- DPRINT("UpdateFileNameRecord(%p, %I64d, %wZ, %u, %I64u, %I64u)\n", Vcb, ParentMFTIndex, FileName, DirSearch, NewDataSize, NewAllocationSize);
+ DPRINT("UpdateFileNameRecord(%p, %I64d, %wZ, %u, %I64u, %I64u, %s)\n",
+ Vcb,
+ ParentMFTIndex,
+ FileName,
+ DirSearch,
+ NewDataSize,
+ NewAllocationSize,
+ CaseSensitive ? "TRUE" : "FALSE");
MftRecord = ExAllocatePoolWithTag(NonPagedPool,
Vcb->NtfsInfo.BytesPerFileRecord,
&CurrentEntry,
DirSearch,
NewDataSize,
- NewAllocationSize);
+ NewAllocationSize,
+ CaseSensitive);
ReleaseAttributeContext(IndexRootCtx);
ExFreePoolWithTag(IndexRecord, TAG_NTFS);
PULONG CurrentEntry,
BOOLEAN DirSearch,
ULONGLONG NewDataSize,
- ULONGLONG NewAllocatedSize)
+ ULONGLONG NewAllocatedSize,
+ BOOLEAN CaseSensitive)
{
NTSTATUS Status;
ULONG RecordOffset;
if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) > 0x10 &&
*CurrentEntry >= *StartEntry &&
IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
- CompareFileName(FileName, IndexEntry, DirSearch))
+ CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
{
*StartEntry = *CurrentEntry;
IndexEntry->FileName.DataSize = NewDataSize;
LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.TotalSizeOfEntries);
ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexBuffer + IndexBlockSize));
- Status = UpdateIndexEntryFileNameSize(NULL, NULL, NULL, 0, FirstEntry, LastEntry, FileName, StartEntry, CurrentEntry, DirSearch, NewDataSize, NewAllocatedSize);
+ Status = UpdateIndexEntryFileNameSize(NULL,
+ NULL,
+ NULL,
+ 0,
+ FirstEntry,
+ LastEntry,
+ FileName,
+ StartEntry,
+ CurrentEntry,
+ DirSearch,
+ NewDataSize,
+ NewAllocatedSize,
+ CaseSensitive);
if (Status == STATUS_PENDING)
{
// write the index record back to disk
* @param DestinationIndex
* Pointer to a ULONGLONG which will receive the MFT index where the file record was stored.
*
+* @param CanWait
+* Boolean 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.
+*
* @return
* 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)
+ PULONGLONG DestinationIndex,
+ BOOLEAN CanWait)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONGLONG MftIndex;
LARGE_INTEGER BitmapBits;
UCHAR SystemReservedBits;
- DPRINT1("AddNewMftEntry(%p, %p, %p)\n", FileRecord, DeviceExt, DestinationIndex);
+ DPRINT1("AddNewMftEntry(%p, %p, %p, %s)\n", FileRecord, DeviceExt, DestinationIndex, CanWait ? "TRUE" : "FALSE");
// First, we have to read the mft's $Bitmap attribute
Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
ReleaseAttributeContext(BitmapContext);
// Couldn't find a free record in the MFT, add some blank records and try again
- Status = IncreaseMftSize(DeviceExt);
+ Status = IncreaseMftSize(DeviceExt, CanWait);
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Couldn't find space in MFT for file or increase MFT size!\n");
return Status;
}
- return AddNewMftEntry(FileRecord, DeviceExt, DestinationIndex);
+ return AddNewMftEntry(FileRecord, DeviceExt, DestinationIndex, CanWait);
}
DPRINT1("Creating file record at MFT index: %I64u\n", MftIndex);
BOOLEAN
CompareFileName(PUNICODE_STRING FileName,
PINDEX_ENTRY_ATTRIBUTE IndexEntry,
- BOOLEAN DirSearch)
+ BOOLEAN DirSearch,
+ BOOLEAN CaseSensitive)
{
BOOLEAN Ret, Alloc = FALSE;
UNICODE_STRING EntryName;
if (DirSearch)
{
UNICODE_STRING IntFileName;
- if (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX)
+ if (!CaseSensitive)
{
NT_VERIFY(NT_SUCCESS(RtlUpcaseUnicodeString(&IntFileName, FileName, TRUE)));
Alloc = TRUE;
IntFileName = *FileName;
}
- Ret = FsRtlIsNameInExpression(&IntFileName, &EntryName, (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX), NULL);
+ Ret = FsRtlIsNameInExpression(&IntFileName, &EntryName, !CaseSensitive, NULL);
if (Alloc)
{
}
else
{
- return (RtlCompareUnicodeString(FileName, &EntryName, (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX)) == 0);
+ return (RtlCompareUnicodeString(FileName, &EntryName, !CaseSensitive) == 0);
}
}
PULONG StartEntry,
PULONG CurrentEntry,
BOOLEAN DirSearch,
+ BOOLEAN CaseSensitive,
ULONGLONG *OutMFTIndex)
{
NTSTATUS Status;
ULONGLONG IndexAllocationSize;
PINDEX_BUFFER IndexBuffer;
- DPRINT("BrowseIndexEntries(%p, %p, %p, %u, %p, %p, %wZ, %u, %u, %u, %p)\n", Vcb, MftRecord, IndexRecord, IndexBlockSize, FirstEntry, LastEntry, FileName, *StartEntry, *CurrentEntry, DirSearch, OutMFTIndex);
+ DPRINT("BrowseIndexEntries(%p, %p, %p, %u, %p, %p, %wZ, %u, %u, %s, %s, %p)\n",
+ Vcb,
+ MftRecord,
+ IndexRecord,
+ IndexBlockSize,
+ FirstEntry,
+ LastEntry,
+ FileName,
+ *StartEntry,
+ *CurrentEntry,
+ DirSearch ? "TRUE" : "FALSE",
+ CaseSensitive ? "TRUE" : "FALSE",
+ OutMFTIndex);
IndexEntry = FirstEntry;
while (IndexEntry < LastEntry &&
if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= 0x10 &&
*CurrentEntry >= *StartEntry &&
IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
- CompareFileName(FileName, IndexEntry, DirSearch))
+ CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
{
*StartEntry = *CurrentEntry;
*OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.TotalSizeOfEntries);
ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexBuffer + IndexBlockSize));
- Status = BrowseIndexEntries(NULL, NULL, NULL, 0, FirstEntry, LastEntry, FileName, StartEntry, CurrentEntry, DirSearch, OutMFTIndex);
+ Status = BrowseIndexEntries(NULL,
+ NULL,
+ NULL,
+ 0,
+ FirstEntry,
+ LastEntry,
+ FileName,
+ StartEntry,
+ CurrentEntry,
+ DirSearch,
+ CaseSensitive,
+ OutMFTIndex);
if (NT_SUCCESS(Status))
{
break;
PUNICODE_STRING FileName,
PULONG FirstEntry,
BOOLEAN DirSearch,
- ULONGLONG *OutMFTIndex)
+ ULONGLONG *OutMFTIndex,
+ BOOLEAN CaseSensitive)
{
PFILE_RECORD_HEADER MftRecord;
PNTFS_ATTR_CONTEXT IndexRootCtx;
DPRINT("IndexRecordSize: %x IndexBlockSize: %x\n", Vcb->NtfsInfo.BytesPerIndexRecord, IndexRoot->SizeOfEntry);
- Status = BrowseIndexEntries(Vcb, MftRecord, IndexRecord, IndexRoot->SizeOfEntry, IndexEntry, IndexEntryEnd, FileName, FirstEntry, &CurrentEntry, DirSearch, OutMFTIndex);
+ Status = BrowseIndexEntries(Vcb,
+ MftRecord,
+ IndexRecord,
+ IndexRoot->SizeOfEntry,
+ IndexEntry,
+ IndexEntryEnd,
+ FileName,
+ FirstEntry,
+ &CurrentEntry,
+ DirSearch,
+ CaseSensitive,
+ OutMFTIndex);
ExFreePoolWithTag(IndexRecord, TAG_NTFS);
ExFreePoolWithTag(MftRecord, TAG_NTFS);
NTSTATUS
NtfsLookupFileAt(PDEVICE_EXTENSION Vcb,
PUNICODE_STRING PathName,
+ BOOLEAN CaseSensitive,
PFILE_RECORD_HEADER *FileRecord,
PULONGLONG MFTIndex,
ULONGLONG CurrentMFTIndex)
NTSTATUS Status;
ULONG FirstEntry = 0;
- DPRINT("NtfsLookupFileAt(%p, %wZ, %p, %I64x)\n", Vcb, PathName, FileRecord, CurrentMFTIndex);
+ DPRINT("NtfsLookupFileAt(%p, %wZ, %s, %p, %p, %I64x)\n",
+ Vcb,
+ PathName,
+ CaseSensitive ? "TRUE" : "FALSE",
+ FileRecord,
+ MFTIndex,
+ CurrentMFTIndex);
FsRtlDissectName(*PathName, &Current, &Remaining);
{
DPRINT("Current: %wZ\n", &Current);
- Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, &Current, &FirstEntry, FALSE, &CurrentMFTIndex);
+ Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, &Current, &FirstEntry, FALSE, &CurrentMFTIndex, CaseSensitive);
if (!NT_SUCCESS(Status))
{
return Status;
NTSTATUS
NtfsLookupFile(PDEVICE_EXTENSION Vcb,
PUNICODE_STRING PathName,
+ BOOLEAN CaseSensitive,
PFILE_RECORD_HEADER *FileRecord,
PULONGLONG MFTIndex)
{
- return NtfsLookupFileAt(Vcb, PathName, FileRecord, MFTIndex, NTFS_FILE_ROOT);
+ return NtfsLookupFileAt(Vcb, PathName, CaseSensitive, FileRecord, MFTIndex, NTFS_FILE_ROOT);
}
/**
PULONG FirstEntry,
PFILE_RECORD_HEADER *FileRecord,
PULONGLONG MFTIndex,
- ULONGLONG CurrentMFTIndex)
+ ULONGLONG CurrentMFTIndex,
+ BOOLEAN CaseSensitive)
{
NTSTATUS Status;
- DPRINT("NtfsFindFileAt(%p, %wZ, %u, %p, %p, %I64x)\n", Vcb, SearchPattern, *FirstEntry, FileRecord, MFTIndex, CurrentMFTIndex);
+ DPRINT("NtfsFindFileAt(%p, %wZ, %u, %p, %p, %I64x, %s)\n",
+ Vcb,
+ SearchPattern,
+ *FirstEntry,
+ FileRecord,
+ MFTIndex,
+ CurrentMFTIndex,
+ (CaseSensitive ? "TRUE" : "FALSE"));
- Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, SearchPattern, FirstEntry, TRUE, &CurrentMFTIndex);
+ Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, SearchPattern, FirstEntry, TRUE, &CurrentMFTIndex, CaseSensitive);
if (!NT_SUCCESS(Status))
{
DPRINT("NtfsFindFileAt: NtfsFindMftRecord() failed with status 0x%08lx\n", Status);