ReactOS 0.4.16-dev-334-g4d9f67c
mft.c
Go to the documentation of this file.
1/*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2014 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/mft.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMERS: Eric Kohl
24 * Valentin Verkhovsky
25 * Pierre Schweitzer (pierre@reactos.org)
26 * Hervé Poussineau (hpoussin@reactos.org)
27 * Trevor Thompson
28 */
29
30/* INCLUDES *****************************************************************/
31
32#include "ntfs.h"
33#include <ntintsafe.h>
34
35#define NDEBUG
36#include <debug.h>
37
38/* FUNCTIONS ****************************************************************/
39
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
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}
101
102
103VOID
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}
118
119
132 PFILE_RECORD_HEADER MftRecord,
133 ULONG Type,
134 PCWSTR Name,
135 ULONG NameLength,
136 PNTFS_ATTR_CONTEXT * AttrCtx,
138{
142 PNTFS_ATTR_RECORD Attribute;
143 PNTFS_ATTRIBUTE_LIST_ITEM AttrListItem;
144
145 DPRINT("FindAttribute(%p, %p, 0x%x, %S, %lu, %p, %p)\n", Vcb, MftRecord, Type, Name, NameLength, AttrCtx, Offset);
146
147 Found = FALSE;
148 Status = FindFirstAttribute(&Context, Vcb, MftRecord, FALSE, &Attribute);
149 while (NT_SUCCESS(Status))
150 {
151 if (Attribute->Type == Type && Attribute->NameLength == NameLength)
152 {
153 if (NameLength != 0)
154 {
155 PWCHAR AttrName;
156
157 AttrName = (PWCHAR)((PCHAR)Attribute + Attribute->NameOffset);
158 DPRINT("%.*S, %.*S\n", Attribute->NameLength, AttrName, NameLength, Name);
159 if (RtlCompareMemory(AttrName, Name, NameLength * sizeof(WCHAR)) == (NameLength * sizeof(WCHAR)))
160 {
161 Found = TRUE;
162 }
163 }
164 else
165 {
166 Found = TRUE;
167 }
168
169 if (Found)
170 {
171 /* Found it, fill up the context and return. */
172 DPRINT("Found context\n");
173 *AttrCtx = PrepareAttributeContext(Attribute);
174
175 (*AttrCtx)->FileMFTIndex = MftRecord->MFTRecordNumber;
176
177 if (Offset != NULL)
178 *Offset = Context.Offset;
179
181 return STATUS_SUCCESS;
182 }
183 }
184
185 Status = FindNextAttribute(&Context, &Attribute);
186 }
187
188 /* No attribute found, check if it is referenced in another file record */
189 Status = FindFirstAttributeListItem(&Context, &AttrListItem);
190 while (NT_SUCCESS(Status))
191 {
192 if (AttrListItem->Type == Type && AttrListItem->NameLength == NameLength)
193 {
194 if (NameLength != 0)
195 {
196 PWCHAR AttrName;
197
198 AttrName = (PWCHAR)((PCHAR)AttrListItem + AttrListItem->NameOffset);
199 DPRINT("%.*S, %.*S\n", AttrListItem->NameLength, AttrName, NameLength, Name);
200 if (RtlCompareMemory(AttrName, Name, NameLength * sizeof(WCHAR)) == (NameLength * sizeof(WCHAR)))
201 {
202 Found = TRUE;
203 }
204 }
205 else
206 {
207 Found = TRUE;
208 }
209
210 if (Found == TRUE)
211 {
212 /* Get the MFT Index of attribute */
213 ULONGLONG MftIndex;
214 PFILE_RECORD_HEADER RemoteHdr;
215
216 MftIndex = AttrListItem->MFTIndex & NTFS_MFT_MASK;
217 RemoteHdr = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
218
219 if (RemoteHdr == NULL)
220 {
223 }
224
225 /* Check we are not reading ourselves */
226 if (MftRecord->MFTRecordNumber == MftIndex)
227 {
228 DPRINT1("Attribute list references missing attribute to this file entry !");
229 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, RemoteHdr);
232 }
233 /* Read the new file record */
234 ReadFileRecord(Vcb, MftIndex, RemoteHdr);
235 Status = FindAttribute(Vcb, RemoteHdr, Type, Name, NameLength, AttrCtx, Offset);
236 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, RemoteHdr);
238 return Status;
239 }
240 }
241 Status = FindNextAttributeListItem(&Context, &AttrListItem);
242 }
245}
246
247
250{
251 if (AttrRecord->IsNonResident)
252 return AttrRecord->NonResident.AllocatedSize;
253 else
254 return ALIGN_UP_BY(AttrRecord->Resident.ValueLength, ATTR_RECORD_ALIGNMENT);
255}
256
257
260{
261 if (AttrRecord->IsNonResident)
262 return AttrRecord->NonResident.DataSize;
263 else
264 return AttrRecord->Resident.ValueLength;
265}
266
294{
295 PNTFS_ATTR_CONTEXT BitmapContext;
296 LARGE_INTEGER BitmapSize;
298 LONGLONG BitmapSizeDifference;
299 ULONG NewRecords = ATTR_RECORD_ALIGNMENT * 8; // Allocate one new record for every bit of every byte we'll be adding to the bitmap
300 ULONG DataSizeDifference = Vcb->NtfsInfo.BytesPerFileRecord * NewRecords;
301 ULONG BitmapOffset;
303 ULONGLONG BitmapBytes;
304 ULONGLONG NewBitmapSize;
305 ULONGLONG FirstNewMftIndex;
307 ULONG LengthWritten;
308 PFILE_RECORD_HEADER BlankFileRecord;
309 ULONG i;
311
312 DPRINT1("IncreaseMftSize(%p, %s)\n", Vcb, CanWait ? "TRUE" : "FALSE");
313
314 // We need exclusive access to the mft while we change its size
315 if (!ExAcquireResourceExclusiveLite(&(Vcb->DirResource), CanWait))
316 {
317 return STATUS_CANT_WAIT;
318 }
319
320 // Create a blank file record that will be used later
321 BlankFileRecord = NtfsCreateEmptyFileRecord(Vcb);
322 if (!BlankFileRecord)
323 {
324 DPRINT1("Error: Unable to create empty file record!\n");
326 }
327
328 // Clear the flags (file record is not in use)
329 BlankFileRecord->Flags = 0;
330
331 // Find the bitmap attribute of master file table
332 Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
333 if (!NT_SUCCESS(Status))
334 {
335 DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
336 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
337 ExReleaseResourceLite(&(Vcb->DirResource));
338 return Status;
339 }
340
341 // Get size of Bitmap Attribute
342 BitmapSize.QuadPart = AttributeDataLength(BitmapContext->pRecord);
343
344 // Calculate the new mft size
345 DataSize.QuadPart = AttributeDataLength(Vcb->MFTContext->pRecord) + DataSizeDifference;
346
347 // Find the index of the first Mft entry that will be created
348 FirstNewMftIndex = AttributeDataLength(Vcb->MFTContext->pRecord) / Vcb->NtfsInfo.BytesPerFileRecord;
349
350 // Determine how many bytes will make up the bitmap
351 BitmapBytes = DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord / 8;
352 if ((DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord) % 8 != 0)
353 BitmapBytes++;
354
355 // Windows will always keep the number of bytes in a bitmap as a multiple of 8, so no bytes are wasted on slack
356 BitmapBytes = ALIGN_UP_BY(BitmapBytes, ATTR_RECORD_ALIGNMENT);
357
358 // Determine how much we need to adjust the bitmap size (it's possible we don't)
359 BitmapSizeDifference = BitmapBytes - BitmapSize.QuadPart;
360 NewBitmapSize = max(BitmapSize.QuadPart + BitmapSizeDifference, BitmapSize.QuadPart);
361
362 // Allocate memory for the bitmap
364 if (!BitmapBuffer)
365 {
366 DPRINT1("ERROR: Unable to allocate memory for bitmap attribute!\n");
367 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
368 ExReleaseResourceLite(&(Vcb->DirResource));
369 ReleaseAttributeContext(BitmapContext);
371 }
372
373 // Zero the bytes we'll be adding
374 RtlZeroMemory(BitmapBuffer, NewBitmapSize);
375
376 // Read the bitmap attribute
378 BitmapContext,
379 0,
381 BitmapSize.LowPart);
382 if (BytesRead != BitmapSize.LowPart)
383 {
384 DPRINT1("ERROR: Bytes read != Bitmap size!\n");
385 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
386 ExReleaseResourceLite(&(Vcb->DirResource));
388 ReleaseAttributeContext(BitmapContext);
390 }
391
392 // Increase the mft size
393 Status = SetNonResidentAttributeDataLength(Vcb, Vcb->MFTContext, Vcb->MftDataOffset, Vcb->MasterFileTable, &DataSize);
394 if (!NT_SUCCESS(Status))
395 {
396 DPRINT1("ERROR: Failed to set size of $MFT data attribute!\n");
397 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
398 ExReleaseResourceLite(&(Vcb->DirResource));
400 ReleaseAttributeContext(BitmapContext);
401 return Status;
402 }
403
404 // We'll need to find the bitmap again, because its offset will have changed after resizing the data attribute
405 ReleaseAttributeContext(BitmapContext);
406 Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, &BitmapOffset);
407 if (!NT_SUCCESS(Status))
408 {
409 DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
410 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
411 ExReleaseResourceLite(&(Vcb->DirResource));
412 return Status;
413 }
414
415 // If the bitmap grew
416 if (BitmapSizeDifference > 0)
417 {
418 // Set the new bitmap size
419 BitmapSize.QuadPart = NewBitmapSize;
420 if (BitmapContext->pRecord->IsNonResident)
421 Status = SetNonResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize);
422 else
423 Status = SetResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize);
424
425 if (!NT_SUCCESS(Status))
426 {
427 DPRINT1("ERROR: Failed to set size of bitmap attribute!\n");
428 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
429 ExReleaseResourceLite(&(Vcb->DirResource));
431 ReleaseAttributeContext(BitmapContext);
432 return Status;
433 }
434 }
435
436 NtfsDumpFileAttributes(Vcb, Vcb->MasterFileTable);
437
438 // Update the file record with the new attribute sizes
439 Status = UpdateFileRecord(Vcb, Vcb->VolumeFcb->MFTIndex, Vcb->MasterFileTable);
440 if (!NT_SUCCESS(Status))
441 {
442 DPRINT1("ERROR: Failed to update $MFT file record!\n");
443 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
444 ExReleaseResourceLite(&(Vcb->DirResource));
446 ReleaseAttributeContext(BitmapContext);
447 return Status;
448 }
449
450 // Write out the new bitmap
451 Status = WriteAttribute(Vcb, BitmapContext, 0, BitmapBuffer, NewBitmapSize, &LengthWritten, Vcb->MasterFileTable);
452 if (!NT_SUCCESS(Status))
453 {
454 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
455 ExReleaseResourceLite(&(Vcb->DirResource));
457 ReleaseAttributeContext(BitmapContext);
458 DPRINT1("ERROR: Couldn't write to bitmap attribute of $MFT!\n");
459 return Status;
460 }
461
462 // Create blank records for the new file record entries.
463 for (i = 0; i < NewRecords; i++)
464 {
465 Status = UpdateFileRecord(Vcb, FirstNewMftIndex + i, BlankFileRecord);
466 if (!NT_SUCCESS(Status))
467 {
468 DPRINT1("ERROR: Failed to write blank file record!\n");
469 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
470 ExReleaseResourceLite(&(Vcb->DirResource));
472 ReleaseAttributeContext(BitmapContext);
473 return Status;
474 }
475 }
476
477 // Update the mft mirror
479
480 // Cleanup
481 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, BlankFileRecord);
482 ExReleaseResourceLite(&(Vcb->DirResource));
484 ReleaseAttributeContext(BitmapContext);
485
486 return Status;
487}
488
513 PNTFS_ATTR_RECORD FirstAttributeToMove,
514 ULONG FirstAttributeOffset,
515 ULONG_PTR MoveTo)
516{
517 // Get the size of all attributes after this one
518 ULONG MemBlockSize = 0;
519 PNTFS_ATTR_RECORD CurrentAttribute = FirstAttributeToMove;
520 ULONG CurrentOffset = FirstAttributeOffset;
521 PNTFS_ATTR_RECORD FinalAttribute;
522
523 while (CurrentAttribute->Type != AttributeEnd && CurrentOffset < DeviceExt->NtfsInfo.BytesPerFileRecord)
524 {
525 CurrentOffset += CurrentAttribute->Length;
526 MemBlockSize += CurrentAttribute->Length;
527 CurrentAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)CurrentAttribute + CurrentAttribute->Length);
528 }
529
530 FinalAttribute = (PNTFS_ATTR_RECORD)(MoveTo + MemBlockSize);
531 MemBlockSize += sizeof(ULONG) * 2; // Add the AttributeEnd and file record end
532
533 ASSERT(MemBlockSize % ATTR_RECORD_ALIGNMENT == 0);
534
535 // Move the attributes after this one
536 RtlMoveMemory((PCHAR)MoveTo, FirstAttributeToMove, MemBlockSize);
537
538 return FinalAttribute;
539}
540
543 PNTFS_ATTR_CONTEXT AttrContext,
544 PFILE_RECORD_HEADER FileRecord,
545 ULONG AttrOffset,
547{
548 PNTFS_ATTR_RECORD Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
550 PNTFS_ATTR_RECORD FinalAttribute;
551 ULONG OldAttributeLength = Destination->Length;
552 ULONG NextAttributeOffset;
553
554 DPRINT1("InternalSetResidentAttributeLength( %p, %p, %p, %lu, %lu )\n", DeviceExt, AttrContext, FileRecord, AttrOffset, DataSize);
555
556 ASSERT(!AttrContext->pRecord->IsNonResident);
557
558 // Update ValueLength Field
559 Destination->Resident.ValueLength = DataSize;
560
561 // Calculate the record length and end marker offset
562 Destination->Length = ALIGN_UP_BY(DataSize + AttrContext->pRecord->Resident.ValueOffset, ATTR_RECORD_ALIGNMENT);
563 NextAttributeOffset = AttrOffset + Destination->Length;
564
565 // Ensure NextAttributeOffset is aligned to an 8-byte boundary
566 ASSERT(NextAttributeOffset % ATTR_RECORD_ALIGNMENT == 0);
567
568 // Will the new attribute be larger than the old one?
569 if (Destination->Length > OldAttributeLength)
570 {
571 // Free the old copy of the attribute in the context, as it will be the wrong length
572 ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS);
573
574 // Create a new copy of the attribute record for the context
576 if (!AttrContext->pRecord)
577 {
578 DPRINT1("Unable to allocate memory for attribute!\n");
580 }
581 RtlZeroMemory((PVOID)((ULONG_PTR)AttrContext->pRecord + OldAttributeLength), Destination->Length - OldAttributeLength);
582 RtlCopyMemory(AttrContext->pRecord, Destination, OldAttributeLength);
583 }
584
585 // Are there attributes after this one that need to be moved?
586 if (NextAttribute->Type != AttributeEnd)
587 {
588 // Move the attributes after this one
589 FinalAttribute = MoveAttributes(DeviceExt, NextAttribute, NextAttributeOffset, (ULONG_PTR)Destination + Destination->Length);
590 }
591 else
592 {
593 // advance to the final "attribute," adjust for the changed length of the attribute we're resizing
594 FinalAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute - OldAttributeLength + Destination->Length);
595 }
596
597 // Update pRecord's length
598 AttrContext->pRecord->Length = Destination->Length;
599 AttrContext->pRecord->Resident.ValueLength = DataSize;
600
601 // set the file record end
602 SetFileRecordEnd(FileRecord, FinalAttribute, FILE_RECORD_END);
603
604 //NtfsDumpFileRecord(DeviceExt, FileRecord);
605
606 return STATUS_SUCCESS;
607}
608
617 PNTFS_ATTR_CONTEXT AttrContext,
618 ULONG AttrOffset,
619 PFILE_RECORD_HEADER FileRecord,
621{
623
624 DPRINT1("SetAttributeDataLength(%p, %p, %p, %lu, %p, %I64u)\n",
626 Fcb,
627 AttrContext,
628 AttrOffset,
629 FileRecord,
630 DataSize->QuadPart);
631
632 // are we truncating the file?
633 if (DataSize->QuadPart < AttributeDataLength(AttrContext->pRecord))
634 {
635 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer, DataSize))
636 {
637 DPRINT1("Can't truncate a memory-mapped file!\n");
639 }
640 }
641
642 if (AttrContext->pRecord->IsNonResident)
643 {
645 AttrContext,
646 AttrOffset,
647 FileRecord,
648 DataSize);
649 }
650 else
651 {
652 // resident attribute
654 AttrContext,
655 AttrOffset,
656 FileRecord,
657 DataSize);
658 }
659
660 if (!NT_SUCCESS(Status))
661 {
662 DPRINT1("ERROR: Failed to set size of attribute!\n");
663 return Status;
664 }
665
666 //NtfsDumpFileAttributes(Fcb->Vcb, FileRecord);
667
668 // write the updated file record back to disk
669 Status = UpdateFileRecord(Fcb->Vcb, Fcb->MFTIndex, FileRecord);
670
671 if (NT_SUCCESS(Status))
672 {
673 if (AttrContext->pRecord->IsNonResident)
674 Fcb->RFCB.AllocationSize.QuadPart = AttrContext->pRecord->NonResident.AllocatedSize;
675 else
680 }
681
682 return STATUS_SUCCESS;
683}
684
705VOID
707 PNTFS_ATTR_RECORD AttrEnd,
708 ULONG EndMarker)
709{
710 // Ensure AttrEnd is aligned on an 8-byte boundary, relative to FileRecord
711 ASSERT(((ULONG_PTR)AttrEnd - (ULONG_PTR)FileRecord) % ATTR_RECORD_ALIGNMENT == 0);
712
713 // mark the end of attributes
714 AttrEnd->Type = AttributeEnd;
715
716 // Restore the "file-record-end marker." The value is never checked but this behavior is consistent with Win2k3.
717 AttrEnd->Length = EndMarker;
718
719 // recalculate bytes in use
720 FileRecord->BytesInUse = (ULONG_PTR)AttrEnd - (ULONG_PTR)FileRecord + sizeof(ULONG) * 2;
721}
722
757 PNTFS_ATTR_CONTEXT AttrContext,
758 ULONG AttrOffset,
759 PFILE_RECORD_HEADER FileRecord,
761{
763 ULONG BytesPerCluster = Vcb->NtfsInfo.BytesPerCluster;
764 ULONGLONG AllocationSize = ROUND_UP(DataSize->QuadPart, BytesPerCluster);
765 PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
766 ULONG ExistingClusters = AttrContext->pRecord->NonResident.AllocatedSize / BytesPerCluster;
767
768 ASSERT(AttrContext->pRecord->IsNonResident);
769
770 // do we need to increase the allocation size?
771 if (AttrContext->pRecord->NonResident.AllocatedSize < AllocationSize)
772 {
773 ULONG ClustersNeeded = (AllocationSize / BytesPerCluster) - ExistingClusters;
774 LARGE_INTEGER LastClusterInDataRun;
775 ULONG NextAssignedCluster;
776 ULONG AssignedClusters;
777
778 if (ExistingClusters == 0)
779 {
780 LastClusterInDataRun.QuadPart = 0;
781 }
782 else
783 {
784 if (!FsRtlLookupLargeMcbEntry(&AttrContext->DataRunsMCB,
785 (LONGLONG)AttrContext->pRecord->NonResident.HighestVCN,
786 (PLONGLONG)&LastClusterInDataRun.QuadPart,
787 NULL,
788 NULL,
789 NULL,
790 NULL))
791 {
792 DPRINT1("Error looking up final large MCB entry!\n");
793
794 // Most likely, HighestVCN went above the largest mapping
795 DPRINT1("Highest VCN of record: %I64u\n", AttrContext->pRecord->NonResident.HighestVCN);
797 }
798 }
799
800 DPRINT("LastClusterInDataRun: %I64u\n", LastClusterInDataRun.QuadPart);
801 DPRINT("Highest VCN of record: %I64u\n", AttrContext->pRecord->NonResident.HighestVCN);
802
803 while (ClustersNeeded > 0)
804 {
806 LastClusterInDataRun.LowPart + 1,
807 ClustersNeeded,
808 &NextAssignedCluster,
809 &AssignedClusters);
810
811 if (!NT_SUCCESS(Status))
812 {
813 DPRINT1("Error: Unable to allocate requested clusters!\n");
814 return Status;
815 }
816
817 // now we need to add the clusters we allocated to the data run
818 Status = AddRun(Vcb, AttrContext, AttrOffset, FileRecord, NextAssignedCluster, AssignedClusters);
819 if (!NT_SUCCESS(Status))
820 {
821 DPRINT1("Error: Unable to add data run!\n");
822 return Status;
823 }
824
825 ClustersNeeded -= AssignedClusters;
826 LastClusterInDataRun.LowPart = NextAssignedCluster + AssignedClusters - 1;
827 }
828 }
829 else if (AttrContext->pRecord->NonResident.AllocatedSize > AllocationSize)
830 {
831 // shrink allocation size
832 ULONG ClustersToFree = ExistingClusters - (AllocationSize / BytesPerCluster);
833 Status = FreeClusters(Vcb, AttrContext, AttrOffset, FileRecord, ClustersToFree);
834 }
835
836 // TODO: is the file compressed, encrypted, or sparse?
837
838 AttrContext->pRecord->NonResident.AllocatedSize = AllocationSize;
839 AttrContext->pRecord->NonResident.DataSize = DataSize->QuadPart;
840 AttrContext->pRecord->NonResident.InitializedSize = DataSize->QuadPart;
841
842 DestinationAttribute->NonResident.AllocatedSize = AllocationSize;
843 DestinationAttribute->NonResident.DataSize = DataSize->QuadPart;
844 DestinationAttribute->NonResident.InitializedSize = DataSize->QuadPart;
845
846 // HighestVCN seems to be set incorrectly somewhere. Apply a hack-fix to reset it.
847 // HACKHACK FIXME: Fix for sparse files; this math won't work in that case.
848 AttrContext->pRecord->NonResident.HighestVCN = ((ULONGLONG)AllocationSize / Vcb->NtfsInfo.BytesPerCluster) - 1;
849 DestinationAttribute->NonResident.HighestVCN = AttrContext->pRecord->NonResident.HighestVCN;
850
851 DPRINT("Allocated Size: %I64u\n", DestinationAttribute->NonResident.AllocatedSize);
852
853 return Status;
854}
855
892 PNTFS_ATTR_CONTEXT AttrContext,
893 ULONG AttrOffset,
894 PFILE_RECORD_HEADER FileRecord,
896{
898
899 // find the next attribute
900 ULONG NextAttributeOffset = AttrOffset + AttrContext->pRecord->Length;
901 PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((PCHAR)FileRecord + NextAttributeOffset);
902
903 ASSERT(!AttrContext->pRecord->IsNonResident);
904
905 //NtfsDumpFileAttributes(Vcb, FileRecord);
906
907 // Do we need to increase the data length?
908 if (DataSize->QuadPart > AttrContext->pRecord->Resident.ValueLength)
909 {
910 // There's usually padding at the end of a record. Do we need to extend past it?
911 ULONG MaxValueLength = AttrContext->pRecord->Length - AttrContext->pRecord->Resident.ValueOffset;
912 if (MaxValueLength < DataSize->LowPart)
913 {
914 // If this is the last attribute, we could move the end marker to the very end of the file record
915 MaxValueLength += Vcb->NtfsInfo.BytesPerFileRecord - NextAttributeOffset - (sizeof(ULONG) * 2);
916
917 if (MaxValueLength < DataSize->LowPart || NextAttribute->Type != AttributeEnd)
918 {
919 // convert attribute to non-resident
920 PNTFS_ATTR_RECORD Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
921 PNTFS_ATTR_RECORD NewRecord;
922 LARGE_INTEGER AttribDataSize;
923 PVOID AttribData;
924 ULONG NewRecordLength;
925 ULONG EndAttributeOffset;
926 ULONG LengthWritten;
927
928 DPRINT1("Converting attribute to non-resident.\n");
929
930 AttribDataSize.QuadPart = AttrContext->pRecord->Resident.ValueLength;
931
932 // Is there existing data we need to back-up?
933 if (AttribDataSize.QuadPart > 0)
934 {
935 AttribData = ExAllocatePoolWithTag(NonPagedPool, AttribDataSize.QuadPart, TAG_NTFS);
936 if (AttribData == NULL)
937 {
938 DPRINT1("ERROR: Couldn't allocate memory for attribute data. Can't migrate to non-resident!\n");
940 }
941
942 // read data to temp buffer
943 Status = ReadAttribute(Vcb, AttrContext, 0, AttribData, AttribDataSize.QuadPart);
944 if (!NT_SUCCESS(Status))
945 {
946 DPRINT1("ERROR: Unable to read attribute before migrating!\n");
947 ExFreePoolWithTag(AttribData, TAG_NTFS);
948 return Status;
949 }
950 }
951
952 // Start by turning this attribute into a 0-length, non-resident attribute, then enlarge it.
953
954 // The size of a 0-length, non-resident attribute will be 0x41 + the size of the attribute name, aligned to an 8-byte boundary
955 NewRecordLength = ALIGN_UP_BY(0x41 + (AttrContext->pRecord->NameLength * sizeof(WCHAR)), ATTR_RECORD_ALIGNMENT);
956
957 // Create a new attribute record that will store the 0-length, non-resident attribute
958 NewRecord = ExAllocatePoolWithTag(NonPagedPool, NewRecordLength, TAG_NTFS);
959
960 // Zero out the NonResident structure
961 RtlZeroMemory(NewRecord, NewRecordLength);
962
963 // Copy the data that's common to both non-resident and resident attributes
964 RtlCopyMemory(NewRecord, AttrContext->pRecord, FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.ValueLength));
965
966 // if there's a name
967 if (AttrContext->pRecord->NameLength != 0)
968 {
969 // copy the name
970 // An attribute name will be located at offset 0x18 for a resident attribute, 0x40 for non-resident
971 RtlCopyMemory((PCHAR)((ULONG_PTR)NewRecord + 0x40),
972 (PCHAR)((ULONG_PTR)AttrContext->pRecord + 0x18),
973 AttrContext->pRecord->NameLength * sizeof(WCHAR));
974 }
975
976 // update the mapping pairs offset, which will be 0x40 (size of a non-resident header) + length in bytes of the name
977 NewRecord->NonResident.MappingPairsOffset = 0x40 + (AttrContext->pRecord->NameLength * sizeof(WCHAR));
978
979 // update the end of the file record
980 // calculate position of end markers (1 byte for empty data run)
981 EndAttributeOffset = AttrOffset + NewRecord->NonResident.MappingPairsOffset + 1;
982 EndAttributeOffset = ALIGN_UP_BY(EndAttributeOffset, ATTR_RECORD_ALIGNMENT);
983
984 // Update the length
985 NewRecord->Length = EndAttributeOffset - AttrOffset;
986
987 ASSERT(NewRecord->Length == NewRecordLength);
988
989 // Copy the new attribute record into the file record
990 RtlCopyMemory(Destination, NewRecord, NewRecord->Length);
991
992 // Update the file record end
993 SetFileRecordEnd(FileRecord,
994 (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + EndAttributeOffset),
996
997 // Initialize the MCB, potentially catch an exception
999 {
1000 FsRtlInitializeLargeMcb(&AttrContext->DataRunsMCB, NonPagedPool);
1001 }
1003 {
1004 DPRINT1("Unable to create LargeMcb!\n");
1005 if (AttribDataSize.QuadPart > 0)
1006 ExFreePoolWithTag(AttribData, TAG_NTFS);
1007 ExFreePoolWithTag(NewRecord, TAG_NTFS);
1009 } _SEH2_END;
1010
1011 // Mark the attribute as non-resident (we wait until after we know the LargeMcb was initialized)
1012 NewRecord->IsNonResident = Destination->IsNonResident = 1;
1013
1014 // Update file record on disk
1015 Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord);
1016 if (!NT_SUCCESS(Status))
1017 {
1018 DPRINT1("ERROR: Couldn't update file record to continue migration!\n");
1019 if (AttribDataSize.QuadPart > 0)
1020 ExFreePoolWithTag(AttribData, TAG_NTFS);
1021 ExFreePoolWithTag(NewRecord, TAG_NTFS);
1022 return Status;
1023 }
1024
1025 // Now we need to free the old copy of the attribute record in the context and replace it with the new one
1026 ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS);
1027 AttrContext->pRecord = NewRecord;
1028
1029 // Now we can treat the attribute as non-resident and enlarge it normally
1030 Status = SetNonResidentAttributeDataLength(Vcb, AttrContext, AttrOffset, FileRecord, DataSize);
1031 if (!NT_SUCCESS(Status))
1032 {
1033 DPRINT1("ERROR: Unable to migrate resident attribute!\n");
1034 if (AttribDataSize.QuadPart > 0)
1035 ExFreePoolWithTag(AttribData, TAG_NTFS);
1036 return Status;
1037 }
1038
1039 // restore the back-up attribute, if we made one
1040 if (AttribDataSize.QuadPart > 0)
1041 {
1042 Status = WriteAttribute(Vcb, AttrContext, 0, AttribData, AttribDataSize.QuadPart, &LengthWritten, FileRecord);
1043 if (!NT_SUCCESS(Status))
1044 {
1045 DPRINT1("ERROR: Unable to write attribute data to non-resident clusters during migration!\n");
1046 // TODO: Reverse migration so no data is lost
1047 ExFreePoolWithTag(AttribData, TAG_NTFS);
1048 return Status;
1049 }
1050
1051 ExFreePoolWithTag(AttribData, TAG_NTFS);
1052 }
1053 }
1054 }
1055 }
1056
1057 // set the new length of the resident attribute (if we didn't migrate it)
1058 if (!AttrContext->pRecord->IsNonResident)
1059 return InternalSetResidentAttributeLength(Vcb, AttrContext, FileRecord, AttrOffset, DataSize->LowPart);
1060
1061 return STATUS_SUCCESS;
1062}
1063
1064ULONG
1068 PCHAR Buffer,
1069 ULONG Length)
1070{
1071 ULONGLONG LastLCN;
1072 PUCHAR DataRun;
1073 LONGLONG DataRunOffset;
1074 ULONGLONG DataRunLength;
1075 LONGLONG DataRunStartLCN;
1076 ULONGLONG CurrentOffset;
1078 ULONG AlreadyRead;
1080
1081 //TEMPTEMP
1082 PUCHAR TempBuffer;
1083
1084 if (!Context->pRecord->IsNonResident)
1085 {
1086 // We need to truncate Offset to a ULONG for pointer arithmetic
1087 // The check below should ensure that Offset is well within the range of 32 bits
1088 ULONG LittleOffset = (ULONG)Offset;
1089
1090 // Ensure that offset isn't beyond the end of the attribute
1091 if (Offset > Context->pRecord->Resident.ValueLength)
1092 return 0;
1093 if (Offset + Length > Context->pRecord->Resident.ValueLength)
1094 Length = (ULONG)(Context->pRecord->Resident.ValueLength - Offset);
1095
1096 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Context->pRecord + Context->pRecord->Resident.ValueOffset + LittleOffset), Length);
1097 return Length;
1098 }
1099
1100 /*
1101 * Non-resident attribute
1102 */
1103
1104 /*
1105 * I. Find the corresponding start data run.
1106 */
1107
1108 AlreadyRead = 0;
1109
1110 // FIXME: Cache seems to be non-working. Disable it for now
1111 //if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * Volume->ClusterSize)
1112 if (0)
1113 {
1114 DataRun = Context->CacheRun;
1115 LastLCN = Context->CacheRunLastLCN;
1116 DataRunStartLCN = Context->CacheRunStartLCN;
1117 DataRunLength = Context->CacheRunLength;
1118 CurrentOffset = Context->CacheRunCurrentOffset;
1119 }
1120 else
1121 {
1122 //TEMPTEMP
1123 ULONG UsedBufferSize;
1124 TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
1125 if (TempBuffer == NULL)
1126 {
1128 }
1129
1130 LastLCN = 0;
1131 CurrentOffset = 0;
1132
1133 // This will be rewritten in the next iteration to just use the DataRuns MCB directly
1134 ConvertLargeMCBToDataRuns(&Context->DataRunsMCB,
1135 TempBuffer,
1136 Vcb->NtfsInfo.BytesPerFileRecord,
1137 &UsedBufferSize);
1138
1139 DataRun = TempBuffer;
1140
1141 while (1)
1142 {
1143 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1144 if (DataRunOffset != -1)
1145 {
1146 /* Normal data run. */
1147 DataRunStartLCN = LastLCN + DataRunOffset;
1148 LastLCN = DataRunStartLCN;
1149 }
1150 else
1151 {
1152 /* Sparse data run. */
1153 DataRunStartLCN = -1;
1154 }
1155
1156 if (Offset >= CurrentOffset &&
1157 Offset < CurrentOffset + (DataRunLength * Vcb->NtfsInfo.BytesPerCluster))
1158 {
1159 break;
1160 }
1161
1162 if (*DataRun == 0)
1163 {
1164 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
1165 return AlreadyRead;
1166 }
1167
1168 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1169 }
1170 }
1171
1172 /*
1173 * II. Go through the run list and read the data
1174 */
1175
1176 ReadLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset), Length);
1177 if (DataRunStartLCN == -1)
1178 {
1181 }
1182 else
1183 {
1184 Status = NtfsReadDisk(Vcb->StorageDevice,
1185 DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster + Offset - CurrentOffset,
1186 ReadLength,
1187 Vcb->NtfsInfo.BytesPerSector,
1188 (PVOID)Buffer,
1189 FALSE);
1190 }
1191 if (NT_SUCCESS(Status))
1192 {
1193 Length -= ReadLength;
1194 Buffer += ReadLength;
1195 AlreadyRead += ReadLength;
1196
1197 if (ReadLength == DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset))
1198 {
1199 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1200 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1201 if (DataRunOffset != (ULONGLONG)-1)
1202 {
1203 DataRunStartLCN = LastLCN + DataRunOffset;
1204 LastLCN = DataRunStartLCN;
1205 }
1206 else
1207 DataRunStartLCN = -1;
1208 }
1209
1210 while (Length > 0)
1211 {
1212 ReadLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster, Length);
1213 if (DataRunStartLCN == -1)
1215 else
1216 {
1217 Status = NtfsReadDisk(Vcb->StorageDevice,
1218 DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster,
1219 ReadLength,
1220 Vcb->NtfsInfo.BytesPerSector,
1221 (PVOID)Buffer,
1222 FALSE);
1223 if (!NT_SUCCESS(Status))
1224 break;
1225 }
1226
1227 Length -= ReadLength;
1228 Buffer += ReadLength;
1229 AlreadyRead += ReadLength;
1230
1231 /* We finished this request, but there still data in this data run. */
1232 if (Length == 0 && ReadLength != DataRunLength * Vcb->NtfsInfo.BytesPerCluster)
1233 break;
1234
1235 /*
1236 * Go to next run in the list.
1237 */
1238
1239 if (*DataRun == 0)
1240 break;
1241 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1242 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1243 if (DataRunOffset != -1)
1244 {
1245 /* Normal data run. */
1246 DataRunStartLCN = LastLCN + DataRunOffset;
1247 LastLCN = DataRunStartLCN;
1248 }
1249 else
1250 {
1251 /* Sparse data run. */
1252 DataRunStartLCN = -1;
1253 }
1254 } /* while */
1255
1256 } /* if Disk */
1257
1258 // TEMPTEMP
1259 if (Context->pRecord->IsNonResident)
1260 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
1261
1262 Context->CacheRun = DataRun;
1263 Context->CacheRunOffset = Offset + AlreadyRead;
1264 Context->CacheRunStartLCN = DataRunStartLCN;
1265 Context->CacheRunLength = DataRunLength;
1266 Context->CacheRunLastLCN = LastLCN;
1267 Context->CacheRunCurrentOffset = CurrentOffset;
1268
1269 return AlreadyRead;
1270}
1271
1272
1318 const PUCHAR Buffer,
1319 ULONG Length,
1320 PULONG RealLengthWritten,
1321 PFILE_RECORD_HEADER FileRecord)
1322{
1323 ULONGLONG LastLCN;
1324 PUCHAR DataRun;
1325 LONGLONG DataRunOffset;
1326 ULONGLONG DataRunLength;
1327 LONGLONG DataRunStartLCN;
1328 ULONGLONG CurrentOffset;
1331 PUCHAR SourceBuffer = Buffer;
1333 BOOLEAN FileRecordAllocated = FALSE;
1334
1335 //TEMPTEMP
1336 PUCHAR TempBuffer;
1337
1338
1339 DPRINT("WriteAttribute(%p, %p, %I64u, %p, %lu, %p, %p)\n", Vcb, Context, Offset, Buffer, Length, RealLengthWritten, FileRecord);
1340
1341 *RealLengthWritten = 0;
1342
1343 // is this a resident attribute?
1344 if (!Context->pRecord->IsNonResident)
1345 {
1346 ULONG AttributeOffset;
1347 PNTFS_ATTR_CONTEXT FoundContext;
1349
1350 // Ensure requested data is within the bounds of the attribute
1351 ASSERT(Offset + Length <= Context->pRecord->Resident.ValueLength);
1352
1353 if (Offset + Length > Context->pRecord->Resident.ValueLength)
1354 {
1355 DPRINT1("DRIVER ERROR: Attribute is too small!\n");
1357 }
1358
1359 // Do we need to read the file record?
1360 if (FileRecord == NULL)
1361 {
1362 FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
1363 if (!FileRecord)
1364 {
1365 DPRINT1("Error: Couldn't allocate file record!\n");
1366 return STATUS_NO_MEMORY;
1367 }
1368
1369 FileRecordAllocated = TRUE;
1370
1371 // read the file record
1372 ReadFileRecord(Vcb, Context->FileMFTIndex, FileRecord);
1373 }
1374
1375 // find where to write the attribute data to
1376 Status = FindAttribute(Vcb, FileRecord,
1377 Context->pRecord->Type,
1378 (PCWSTR)((ULONG_PTR)Context->pRecord + Context->pRecord->NameOffset),
1379 Context->pRecord->NameLength,
1380 &FoundContext,
1381 &AttributeOffset);
1382
1383 if (!NT_SUCCESS(Status))
1384 {
1385 DPRINT1("ERROR: Couldn't find matching attribute!\n");
1386 if(FileRecordAllocated)
1387 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
1388 return Status;
1389 }
1390
1391 Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttributeOffset);
1392
1393 DPRINT("Offset: %I64u, AttributeOffset: %u, ValueOffset: %u\n", Offset, AttributeOffset, Context->pRecord->Resident.ValueLength);
1394
1395 // Will we be writing past the end of the allocated file record?
1396 if (Offset + Length + AttributeOffset + Context->pRecord->Resident.ValueOffset > Vcb->NtfsInfo.BytesPerFileRecord)
1397 {
1398 DPRINT1("DRIVER ERROR: Data being written extends past end of file record!\n");
1399 ReleaseAttributeContext(FoundContext);
1400 if (FileRecordAllocated)
1401 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
1403 }
1404
1405 // copy the data being written into the file record. We cast Offset to ULONG, which is safe because it's range has been verified.
1406 RtlCopyMemory((PCHAR)((ULONG_PTR)Destination + Context->pRecord->Resident.ValueOffset + (ULONG)Offset), Buffer, Length);
1407
1408 Status = UpdateFileRecord(Vcb, Context->FileMFTIndex, FileRecord);
1409
1410 // Update the context's copy of the resident attribute
1411 ASSERT(Context->pRecord->Length == Destination->Length);
1412 RtlCopyMemory((PVOID)Context->pRecord, Destination, Context->pRecord->Length);
1413
1414 ReleaseAttributeContext(FoundContext);
1415 if (FileRecordAllocated)
1416 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
1417
1418 if (NT_SUCCESS(Status))
1419 *RealLengthWritten = Length;
1420
1421 return Status;
1422 }
1423
1424 // This is a non-resident attribute.
1425
1426 // I. Find the corresponding start data run.
1427
1428 // FIXME: Cache seems to be non-working. Disable it for now
1429 //if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * Volume->ClusterSize)
1430 /*if (0)
1431 {
1432 DataRun = Context->CacheRun;
1433 LastLCN = Context->CacheRunLastLCN;
1434 DataRunStartLCN = Context->CacheRunStartLCN;
1435 DataRunLength = Context->CacheRunLength;
1436 CurrentOffset = Context->CacheRunCurrentOffset;
1437 }
1438 else*/
1439 {
1440 ULONG UsedBufferSize;
1441 LastLCN = 0;
1442 CurrentOffset = 0;
1443
1444 // This will be rewritten in the next iteration to just use the DataRuns MCB directly
1445 TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
1446 if (TempBuffer == NULL)
1447 {
1449 }
1450
1451 ConvertLargeMCBToDataRuns(&Context->DataRunsMCB,
1452 TempBuffer,
1453 Vcb->NtfsInfo.BytesPerFileRecord,
1454 &UsedBufferSize);
1455
1456 DataRun = TempBuffer;
1457
1458 while (1)
1459 {
1460 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1461 if (DataRunOffset != -1)
1462 {
1463 // Normal data run.
1464 // DPRINT1("Writing to normal data run, LastLCN %I64u DataRunOffset %I64d\n", LastLCN, DataRunOffset);
1465 DataRunStartLCN = LastLCN + DataRunOffset;
1466 LastLCN = DataRunStartLCN;
1467 }
1468 else
1469 {
1470 // Sparse data run. We can't support writing to sparse files yet
1471 // (it may require increasing the allocation size).
1472 DataRunStartLCN = -1;
1473 DPRINT1("FIXME: Writing to sparse files is not supported yet!\n");
1475 goto Cleanup;
1476 }
1477
1478 // Have we reached the data run we're trying to write to?
1479 if (Offset >= CurrentOffset &&
1480 Offset < CurrentOffset + (DataRunLength * Vcb->NtfsInfo.BytesPerCluster))
1481 {
1482 break;
1483 }
1484
1485 if (*DataRun == 0)
1486 {
1487 // We reached the last assigned cluster
1488 // TODO: assign new clusters to the end of the file.
1489 // (Presently, this code will rarely be reached, the write will usually have already failed by now)
1490 // [We can reach here by creating a new file record when the MFT isn't large enough]
1491 DPRINT1("FIXME: Master File Table needs to be enlarged.\n");
1493 goto Cleanup;
1494 }
1495
1496 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1497 }
1498 }
1499
1500 // II. Go through the run list and write the data
1501
1502 /* REVIEWME -- As adapted from NtfsReadAttribute():
1503 We seem to be making a special case for the first applicable data run, but I'm not sure why.
1504 Does it have something to do with (not) caching? Is this strategy equally applicable to writing? */
1505
1506 WriteLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset), Length);
1507
1508 StartingOffset = DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster + Offset - CurrentOffset;
1509
1510 // Write the data to the disk
1511 Status = NtfsWriteDisk(Vcb->StorageDevice,
1514 Vcb->NtfsInfo.BytesPerSector,
1515 (PVOID)SourceBuffer);
1516
1517 // Did the write fail?
1518 if (!NT_SUCCESS(Status))
1519 {
1520 Context->CacheRun = DataRun;
1521 Context->CacheRunOffset = Offset;
1522 Context->CacheRunStartLCN = DataRunStartLCN;
1523 Context->CacheRunLength = DataRunLength;
1524 Context->CacheRunLastLCN = LastLCN;
1525 Context->CacheRunCurrentOffset = CurrentOffset;
1526
1527 goto Cleanup;
1528 }
1529
1531 SourceBuffer += WriteLength;
1532 *RealLengthWritten += WriteLength;
1533
1534 // Did we write to the end of the data run?
1535 if (WriteLength == DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset))
1536 {
1537 // Advance to the next data run
1538 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1539 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1540
1541 if (DataRunOffset != (ULONGLONG)-1)
1542 {
1543 DataRunStartLCN = LastLCN + DataRunOffset;
1544 LastLCN = DataRunStartLCN;
1545 }
1546 else
1547 DataRunStartLCN = -1;
1548 }
1549
1550 // Do we have more data to write?
1551 while (Length > 0)
1552 {
1553 // Make sure we don't write past the end of the current data run
1554 WriteLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster, Length);
1555
1556 // Are we dealing with a sparse data run?
1557 if (DataRunStartLCN == -1)
1558 {
1559 DPRINT1("FIXME: Don't know how to write to sparse files yet! (DataRunStartLCN == -1)\n");
1561 goto Cleanup;
1562 }
1563 else
1564 {
1565 // write the data to the disk
1566 Status = NtfsWriteDisk(Vcb->StorageDevice,
1567 DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster,
1569 Vcb->NtfsInfo.BytesPerSector,
1570 (PVOID)SourceBuffer);
1571 if (!NT_SUCCESS(Status))
1572 break;
1573 }
1574
1576 SourceBuffer += WriteLength;
1577 *RealLengthWritten += WriteLength;
1578
1579 // We finished this request, but there's still data in this data run.
1580 if (Length == 0 && WriteLength != DataRunLength * Vcb->NtfsInfo.BytesPerCluster)
1581 break;
1582
1583 // Go to next run in the list.
1584
1585 if (*DataRun == 0)
1586 {
1587 // that was the last run
1588 if (Length > 0)
1589 {
1590 // Failed sanity check.
1591 DPRINT1("Encountered EOF before expected!\n");
1593 goto Cleanup;
1594 }
1595
1596 break;
1597 }
1598
1599 // Advance to the next data run
1600 CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
1601 DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
1602 if (DataRunOffset != -1)
1603 {
1604 // Normal data run.
1605 DataRunStartLCN = LastLCN + DataRunOffset;
1606 LastLCN = DataRunStartLCN;
1607 }
1608 else
1609 {
1610 // Sparse data run.
1611 DataRunStartLCN = -1;
1612 }
1613 } // end while (Length > 0) [more data to write]
1614
1615 Context->CacheRun = DataRun;
1616 Context->CacheRunOffset = Offset + *RealLengthWritten;
1617 Context->CacheRunStartLCN = DataRunStartLCN;
1618 Context->CacheRunLength = DataRunLength;
1619 Context->CacheRunLastLCN = LastLCN;
1620 Context->CacheRunCurrentOffset = CurrentOffset;
1621
1622Cleanup:
1623 // TEMPTEMP
1624 if (Context->pRecord->IsNonResident)
1625 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
1626
1627 return Status;
1628}
1629
1634{
1636
1637 DPRINT("ReadFileRecord(%p, %I64x, %p)\n", Vcb, index, file);
1638
1639 BytesRead = ReadAttribute(Vcb, Vcb->MFTContext, index * Vcb->NtfsInfo.BytesPerFileRecord, (PCHAR)file, Vcb->NtfsInfo.BytesPerFileRecord);
1640 if (BytesRead != Vcb->NtfsInfo.BytesPerFileRecord)
1641 {
1642 DPRINT1("ReadFileRecord failed: %I64u read, %lu expected\n", BytesRead, Vcb->NtfsInfo.BytesPerFileRecord);
1643 return STATUS_PARTIAL_COPY;
1644 }
1645
1646 /* Apply update sequence array fixups. */
1647 DPRINT("Sequence number: %u\n", file->SequenceNumber);
1648 return FixupUpdateSequenceArray(Vcb, &file->Ntfs);
1649}
1650
1651
1661 ULONGLONG ParentMFTIndex,
1663 BOOLEAN DirSearch,
1664 ULONGLONG NewDataSize,
1665 ULONGLONG NewAllocationSize,
1666 BOOLEAN CaseSensitive)
1667{
1668 PFILE_RECORD_HEADER MftRecord;
1669 PNTFS_ATTR_CONTEXT IndexRootCtx;
1670 PINDEX_ROOT_ATTRIBUTE IndexRoot;
1671 PCHAR IndexRecord;
1672 PINDEX_ENTRY_ATTRIBUTE IndexEntry, IndexEntryEnd;
1674 ULONG CurrentEntry = 0;
1675
1676 DPRINT("UpdateFileNameRecord(%p, %I64d, %wZ, %s, %I64u, %I64u, %s)\n",
1677 Vcb,
1678 ParentMFTIndex,
1679 FileName,
1680 DirSearch ? "TRUE" : "FALSE",
1681 NewDataSize,
1682 NewAllocationSize,
1683 CaseSensitive ? "TRUE" : "FALSE");
1684
1685 MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
1686 if (MftRecord == NULL)
1687 {
1689 }
1690
1691 Status = ReadFileRecord(Vcb, ParentMFTIndex, MftRecord);
1692 if (!NT_SUCCESS(Status))
1693 {
1694 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1695 return Status;
1696 }
1697
1698 ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
1699 Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
1700 if (!NT_SUCCESS(Status))
1701 {
1702 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1703 return Status;
1704 }
1705
1706 IndexRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerIndexRecord, TAG_NTFS);
1707 if (IndexRecord == NULL)
1708 {
1709 ReleaseAttributeContext(IndexRootCtx);
1710 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1712 }
1713
1714 Status = ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, AttributeDataLength(IndexRootCtx->pRecord));
1715 if (!NT_SUCCESS(Status))
1716 {
1717 DPRINT1("ERROR: Failed to read Index Root!\n");
1718 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
1719 ReleaseAttributeContext(IndexRootCtx);
1720 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1721 return Status;
1722 }
1723
1724 IndexRoot = (PINDEX_ROOT_ATTRIBUTE)IndexRecord;
1725 IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)&IndexRoot->Header + IndexRoot->Header.FirstEntryOffset);
1726 // Index root is always resident.
1727 IndexEntryEnd = (PINDEX_ENTRY_ATTRIBUTE)(IndexRecord + IndexRoot->Header.TotalSizeOfEntries);
1728
1729 DPRINT("IndexRecordSize: %x IndexBlockSize: %x\n", Vcb->NtfsInfo.BytesPerIndexRecord, IndexRoot->SizeOfEntry);
1730
1732 MftRecord,
1733 IndexRecord,
1734 IndexRoot->SizeOfEntry,
1735 IndexEntry,
1736 IndexEntryEnd,
1737 FileName,
1738 &CurrentEntry,
1739 &CurrentEntry,
1740 DirSearch,
1741 NewDataSize,
1742 NewAllocationSize,
1743 CaseSensitive);
1744
1745 if (Status == STATUS_PENDING)
1746 {
1747 // we need to write the index root attribute back to disk
1748 ULONG LengthWritten;
1749 Status = WriteAttribute(Vcb, IndexRootCtx, 0, (PUCHAR)IndexRecord, AttributeDataLength(IndexRootCtx->pRecord), &LengthWritten, MftRecord);
1750 if (!NT_SUCCESS(Status))
1751 {
1752 DPRINT1("ERROR: Couldn't update Index Root!\n");
1753 }
1754
1755 }
1756
1757 ReleaseAttributeContext(IndexRootCtx);
1758 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
1759 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
1760
1761 return Status;
1762}
1763
1771 PFILE_RECORD_HEADER MftRecord,
1772 PCHAR IndexRecord,
1773 ULONG IndexBlockSize,
1774 PINDEX_ENTRY_ATTRIBUTE FirstEntry,
1775 PINDEX_ENTRY_ATTRIBUTE LastEntry,
1777 PULONG StartEntry,
1778 PULONG CurrentEntry,
1779 BOOLEAN DirSearch,
1780 ULONGLONG NewDataSize,
1781 ULONGLONG NewAllocatedSize,
1782 BOOLEAN CaseSensitive)
1783{
1785 ULONG RecordOffset;
1786 PINDEX_ENTRY_ATTRIBUTE IndexEntry;
1787 PNTFS_ATTR_CONTEXT IndexAllocationCtx;
1788 ULONGLONG IndexAllocationSize;
1789 PINDEX_BUFFER IndexBuffer;
1790
1791 DPRINT("UpdateIndexEntrySize(%p, %p, %p, %lu, %p, %p, %wZ, %lu, %lu, %s, %I64u, %I64u, %s)\n",
1792 Vcb,
1793 MftRecord,
1794 IndexRecord,
1795 IndexBlockSize,
1796 FirstEntry,
1797 LastEntry,
1798 FileName,
1799 *StartEntry,
1800 *CurrentEntry,
1801 DirSearch ? "TRUE" : "FALSE",
1802 NewDataSize,
1803 NewAllocatedSize,
1804 CaseSensitive ? "TRUE" : "FALSE");
1805
1806 // find the index entry responsible for the file we're trying to update
1807 IndexEntry = FirstEntry;
1808 while (IndexEntry < LastEntry &&
1809 !(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
1810 {
1811 if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) > NTFS_FILE_FIRST_USER_FILE &&
1812 *CurrentEntry >= *StartEntry &&
1813 IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
1814 CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
1815 {
1816 *StartEntry = *CurrentEntry;
1817 IndexEntry->FileName.DataSize = NewDataSize;
1818 IndexEntry->FileName.AllocatedSize = NewAllocatedSize;
1819 // indicate that the caller will still need to write the structure to the disk
1820 return STATUS_PENDING;
1821 }
1822
1823 (*CurrentEntry) += 1;
1824 ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
1825 IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
1826 }
1827
1828 /* If we're already browsing a subnode */
1829 if (IndexRecord == NULL)
1830 {
1832 }
1833
1834 /* If there's no subnode */
1835 if (!(IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE))
1836 {
1838 }
1839
1840 Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationCtx, NULL);
1841 if (!NT_SUCCESS(Status))
1842 {
1843 DPRINT("Corrupted filesystem!\n");
1844 return Status;
1845 }
1846
1847 IndexAllocationSize = AttributeDataLength(IndexAllocationCtx->pRecord);
1849 for (RecordOffset = 0; RecordOffset < IndexAllocationSize; RecordOffset += IndexBlockSize)
1850 {
1851 ReadAttribute(Vcb, IndexAllocationCtx, RecordOffset, IndexRecord, IndexBlockSize);
1852 Status = FixupUpdateSequenceArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
1853 if (!NT_SUCCESS(Status))
1854 {
1855 break;
1856 }
1857
1858 IndexBuffer = (PINDEX_BUFFER)IndexRecord;
1859 ASSERT(IndexBuffer->Ntfs.Type == NRH_INDX_TYPE);
1860 ASSERT(IndexBuffer->Header.AllocatedSize + FIELD_OFFSET(INDEX_BUFFER, Header) == IndexBlockSize);
1861 FirstEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.FirstEntryOffset);
1862 LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexBuffer->Header + IndexBuffer->Header.TotalSizeOfEntries);
1863 ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexBuffer + IndexBlockSize));
1864
1866 NULL,
1867 NULL,
1868 0,
1869 FirstEntry,
1870 LastEntry,
1871 FileName,
1872 StartEntry,
1873 CurrentEntry,
1874 DirSearch,
1875 NewDataSize,
1876 NewAllocatedSize,
1877 CaseSensitive);
1878 if (Status == STATUS_PENDING)
1879 {
1880 // write the index record back to disk
1881 ULONG Written;
1882
1883 // first we need to update the fixup values for the index block
1884 Status = AddFixupArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
1885 if (!NT_SUCCESS(Status))
1886 {
1887 DPRINT1("Error: Failed to update fixup sequence array!\n");
1888 break;
1889 }
1890
1891 Status = WriteAttribute(Vcb, IndexAllocationCtx, RecordOffset, (const PUCHAR)IndexRecord, IndexBlockSize, &Written, MftRecord);
1892 if (!NT_SUCCESS(Status))
1893 {
1894 DPRINT1("ERROR Performing write!\n");
1895 break;
1896 }
1897
1899 break;
1900 }
1901 if (NT_SUCCESS(Status))
1902 {
1903 break;
1904 }
1905 }
1906
1907 ReleaseAttributeContext(IndexAllocationCtx);
1908 return Status;
1909}
1910
1932 ULONGLONG MftIndex,
1933 PFILE_RECORD_HEADER FileRecord)
1934{
1937
1938 DPRINT("UpdateFileRecord(%p, 0x%I64x, %p)\n", Vcb, MftIndex, FileRecord);
1939
1940 // Add the fixup array to prepare the data for writing to disk
1941 AddFixupArray(Vcb, &FileRecord->Ntfs);
1942
1943 // write the file record to the master file table
1945 Vcb->MFTContext,
1946 MftIndex * Vcb->NtfsInfo.BytesPerFileRecord,
1947 (const PUCHAR)FileRecord,
1948 Vcb->NtfsInfo.BytesPerFileRecord,
1949 &BytesWritten,
1950 FileRecord);
1951
1952 if (!NT_SUCCESS(Status))
1953 {
1954 DPRINT1("UpdateFileRecord failed: %lu written, %lu expected\n", BytesWritten, Vcb->NtfsInfo.BytesPerFileRecord);
1955 }
1956
1957 // remove the fixup array (so the file record pointer can still be used)
1958 FixupUpdateSequenceArray(Vcb, &FileRecord->Ntfs);
1959
1960 return Status;
1961}
1962
1963
1967{
1968 USHORT *USA;
1969 USHORT USANumber;
1970 USHORT USACount;
1971 USHORT *Block;
1972
1973 USA = (USHORT*)((PCHAR)Record + Record->UsaOffset);
1974 USANumber = *(USA++);
1975 USACount = Record->UsaCount - 1; /* Exclude the USA Number. */
1976 Block = (USHORT*)((PCHAR)Record + Vcb->NtfsInfo.BytesPerSector - 2);
1977
1978 DPRINT("FixupUpdateSequenceArray(%p, %p)\nUSANumber: %u\tUSACount: %u\n", Vcb, Record, USANumber, USACount);
1979
1980 while (USACount)
1981 {
1982 if (*Block != USANumber)
1983 {
1984 DPRINT1("Mismatch with USA: %u read, %u expected\n" , *Block, USANumber);
1985 return STATUS_UNSUCCESSFUL;
1986 }
1987 *Block = *(USA++);
1988 Block = (USHORT*)((PCHAR)Block + Vcb->NtfsInfo.BytesPerSector);
1989 USACount--;
1990 }
1991
1992 return STATUS_SUCCESS;
1993}
1994
2023 PDEVICE_EXTENSION DeviceExt,
2024 PULONGLONG DestinationIndex,
2025 BOOLEAN CanWait)
2026{
2028 ULONGLONG MftIndex;
2030 ULONGLONG BitmapDataSize;
2031 ULONGLONG AttrBytesRead;
2034 ULONG LengthWritten;
2035 PNTFS_ATTR_CONTEXT BitmapContext;
2036 LARGE_INTEGER BitmapBits;
2037 UCHAR SystemReservedBits;
2038
2039 DPRINT1("AddNewMftEntry(%p, %p, %p, %s)\n", FileRecord, DeviceExt, DestinationIndex, CanWait ? "TRUE" : "FALSE");
2040
2041 // First, we have to read the mft's $Bitmap attribute
2042
2043 // Find the attribute
2044 Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
2045 if (!NT_SUCCESS(Status))
2046 {
2047 DPRINT1("ERROR: Couldn't find $Bitmap attribute of master file table!\n");
2048 return Status;
2049 }
2050
2051 // Get size of bitmap
2052 BitmapDataSize = AttributeDataLength(BitmapContext->pRecord);
2053
2054 // RtlInitializeBitmap wants a ULONG-aligned pointer, and wants the memory passed to it to be a ULONG-multiple
2055 // Allocate a buffer for the $Bitmap attribute plus enough to ensure we can get a ULONG-aligned pointer
2056 BitmapBuffer = ExAllocatePoolWithTag(NonPagedPool, BitmapDataSize + sizeof(ULONG), TAG_NTFS);
2057 if (!BitmapBuffer)
2058 {
2059 ReleaseAttributeContext(BitmapContext);
2061 }
2062 RtlZeroMemory(BitmapBuffer, BitmapDataSize + sizeof(ULONG));
2063
2064 // Get a ULONG-aligned pointer for the bitmap itself
2066
2067 // read $Bitmap attribute
2068 AttrBytesRead = ReadAttribute(DeviceExt, BitmapContext, 0, (PCHAR)BitmapData, BitmapDataSize);
2069
2070 if (AttrBytesRead != BitmapDataSize)
2071 {
2072 DPRINT1("ERROR: Unable to read $Bitmap attribute of master file table!\n");
2074 ReleaseAttributeContext(BitmapContext);
2076 }
2077
2078 // We need to backup the bits for records 0x10 - 0x17 (3rd byte of bitmap) and mark these records
2079 // as in-use so we don't assign files to those indices. They're reserved for the system (e.g. ChkDsk).
2080 SystemReservedBits = BitmapData[2];
2081 BitmapData[2] = 0xff;
2082
2083 // Calculate bit count
2084 BitmapBits.QuadPart = AttributeDataLength(DeviceExt->MFTContext->pRecord) /
2085 DeviceExt->NtfsInfo.BytesPerFileRecord;
2086 if (BitmapBits.HighPart != 0)
2087 {
2088 DPRINT1("\tFIXME: bitmap sizes beyond 32bits are not yet supported! (Your NTFS volume is too large)\n");
2091 ReleaseAttributeContext(BitmapContext);
2093 }
2094
2095 // convert buffer into bitmap
2097
2098 // set next available bit, preferrably after 23rd bit
2099 MftIndex = RtlFindClearBitsAndSet(&Bitmap, 1, 24);
2100 if ((LONG)MftIndex == -1)
2101 {
2102 DPRINT1("Couldn't find free space in MFT for file record, increasing MFT size.\n");
2103
2105 ReleaseAttributeContext(BitmapContext);
2106
2107 // Couldn't find a free record in the MFT, add some blank records and try again
2108 Status = IncreaseMftSize(DeviceExt, CanWait);
2109 if (!NT_SUCCESS(Status))
2110 {
2111 DPRINT1("ERROR: Couldn't find space in MFT for file or increase MFT size!\n");
2112 return Status;
2113 }
2114
2115 return AddNewMftEntry(FileRecord, DeviceExt, DestinationIndex, CanWait);
2116 }
2117
2118 DPRINT1("Creating file record at MFT index: %I64u\n", MftIndex);
2119
2120 // update file record with index
2121 FileRecord->MFTRecordNumber = MftIndex;
2122
2123 // [BitmapData should have been updated via RtlFindClearBitsAndSet()]
2124
2125 // Restore the system reserved bits
2126 BitmapData[2] = SystemReservedBits;
2127
2128 // write the bitmap back to the MFT's $Bitmap attribute
2129 Status = WriteAttribute(DeviceExt, BitmapContext, 0, BitmapData, BitmapDataSize, &LengthWritten, FileRecord);
2130 if (!NT_SUCCESS(Status))
2131 {
2132 DPRINT1("ERROR encountered when writing $Bitmap attribute!\n");
2134 ReleaseAttributeContext(BitmapContext);
2135 return Status;
2136 }
2137
2138 // update the file record (write it to disk)
2139 Status = UpdateFileRecord(DeviceExt, MftIndex, FileRecord);
2140
2141 if (!NT_SUCCESS(Status))
2142 {
2143 DPRINT1("ERROR: Unable to write file record!\n");
2145 ReleaseAttributeContext(BitmapContext);
2146 return Status;
2147 }
2148
2149 *DestinationIndex = MftIndex;
2150
2152 ReleaseAttributeContext(BitmapContext);
2153
2154 return Status;
2155}
2156
2193 ULONGLONG DirectoryMftIndex,
2194 ULONGLONG FileReferenceNumber,
2195 PFILENAME_ATTRIBUTE FilenameAttribute,
2196 BOOLEAN CaseSensitive)
2197{
2199 PFILE_RECORD_HEADER ParentFileRecord;
2200 PNTFS_ATTR_CONTEXT IndexRootContext;
2201 PINDEX_ROOT_ATTRIBUTE I30IndexRoot;
2202 ULONG IndexRootOffset;
2203 ULONGLONG I30IndexRootLength;
2204 ULONG LengthWritten;
2205 PINDEX_ROOT_ATTRIBUTE NewIndexRoot;
2206 ULONG AttributeLength;
2207 PNTFS_ATTR_RECORD NextAttribute;
2208 PB_TREE NewTree;
2209 ULONG BtreeIndexLength;
2210 ULONG MaxIndexRootSize;
2211 PB_TREE_KEY NewLeftKey;
2212 PB_TREE_FILENAME_NODE NewRightHandNode;
2213 LARGE_INTEGER MinIndexRootSize;
2214 ULONG NewMaxIndexRootSize;
2215 ULONG NodeSize;
2216
2217 // Allocate memory for the parent directory
2218 ParentFileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
2219 if (!ParentFileRecord)
2220 {
2221 DPRINT1("ERROR: Couldn't allocate memory for file record!\n");
2223 }
2224
2225 // Open the parent directory
2226 Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
2227 if (!NT_SUCCESS(Status))
2228 {
2229 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2230 DPRINT1("ERROR: Couldn't read parent directory with index %I64u\n",
2231 DirectoryMftIndex);
2232 return Status;
2233 }
2234
2235#ifndef NDEBUG
2236 DPRINT1("Dumping old parent file record:\n");
2237 NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
2238#endif
2239
2240 // Find the index root attribute for the directory
2241 Status = FindAttribute(DeviceExt,
2242 ParentFileRecord,
2244 L"$I30",
2245 4,
2246 &IndexRootContext,
2247 &IndexRootOffset);
2248 if (!NT_SUCCESS(Status))
2249 {
2250 DPRINT1("ERROR: Couldn't find $I30 $INDEX_ROOT attribute for parent directory with MFT #: %I64u!\n",
2251 DirectoryMftIndex);
2252 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2253 return Status;
2254 }
2255
2256 // Find the maximum index size given what the file record can hold
2257 // First, find the max index size assuming index root is the last attribute
2258 MaxIndexRootSize = DeviceExt->NtfsInfo.BytesPerFileRecord // Start with the size of a file record
2259 - IndexRootOffset // Subtract the length of everything that comes before index root
2260 - IndexRootContext->pRecord->Resident.ValueOffset // Subtract the length of the attribute header for index root
2261 - sizeof(INDEX_ROOT_ATTRIBUTE) // Subtract the length of the index root header
2262 - (sizeof(ULONG) * 2); // Subtract the length of the file record end marker and padding
2263
2264 // Are there attributes after this one?
2265 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset + IndexRootContext->pRecord->Length);
2266 if (NextAttribute->Type != AttributeEnd)
2267 {
2268 // Find the length of all attributes after this one, not counting the end marker
2269 ULONG LengthOfAttributes = 0;
2270 PNTFS_ATTR_RECORD CurrentAttribute = NextAttribute;
2271 while (CurrentAttribute->Type != AttributeEnd)
2272 {
2273 LengthOfAttributes += CurrentAttribute->Length;
2274 CurrentAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)CurrentAttribute + CurrentAttribute->Length);
2275 }
2276
2277 // Leave room for the existing attributes
2278 MaxIndexRootSize -= LengthOfAttributes;
2279 }
2280
2281 // Allocate memory for the index root data
2282 I30IndexRootLength = AttributeDataLength(IndexRootContext->pRecord);
2283 I30IndexRoot = ExAllocatePoolWithTag(NonPagedPool, I30IndexRootLength, TAG_NTFS);
2284 if (!I30IndexRoot)
2285 {
2286 DPRINT1("ERROR: Couldn't allocate memory for index root attribute!\n");
2287 ReleaseAttributeContext(IndexRootContext);
2288 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2290 }
2291
2292 // Read the Index Root
2293 Status = ReadAttribute(DeviceExt, IndexRootContext, 0, (PCHAR)I30IndexRoot, I30IndexRootLength);
2294 if (!NT_SUCCESS(Status))
2295 {
2296 DPRINT1("ERROR: Couln't read index root attribute for Mft index #%I64u\n", DirectoryMftIndex);
2297 ReleaseAttributeContext(IndexRootContext);
2298 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2299 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2300 return Status;
2301 }
2302
2303 // Convert the index to a B*Tree
2304 Status = CreateBTreeFromIndex(DeviceExt,
2305 ParentFileRecord,
2306 IndexRootContext,
2307 I30IndexRoot,
2308 &NewTree);
2309 if (!NT_SUCCESS(Status))
2310 {
2311 DPRINT1("ERROR: Failed to create B-Tree from Index!\n");
2312 ReleaseAttributeContext(IndexRootContext);
2313 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2314 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2315 return Status;
2316 }
2317
2318#ifndef NDEBUG
2319 DumpBTree(NewTree);
2320#endif
2321
2322 // Insert the key for the file we're adding
2323 Status = NtfsInsertKey(NewTree,
2324 FileReferenceNumber,
2325 FilenameAttribute,
2326 NewTree->RootNode,
2327 CaseSensitive,
2328 MaxIndexRootSize,
2329 I30IndexRoot->SizeOfEntry,
2330 &NewLeftKey,
2331 &NewRightHandNode);
2332 if (!NT_SUCCESS(Status))
2333 {
2334 DPRINT1("ERROR: Failed to insert key into B-Tree!\n");
2335 DestroyBTree(NewTree);
2336 ReleaseAttributeContext(IndexRootContext);
2337 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2338 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2339 return Status;
2340 }
2341
2342#ifndef NDEBUG
2343 DumpBTree(NewTree);
2344#endif
2345
2346 // The root node can't be split
2347 ASSERT(NewLeftKey == NULL);
2348 ASSERT(NewRightHandNode == NULL);
2349
2350 // Convert B*Tree back to Index
2351
2352 // Updating the index allocation can change the size available for the index root,
2353 // And if the index root is demoted, the index allocation will need to be updated again,
2354 // which may change the size available for index root... etc.
2355 // My solution is to decrease index root to the size it would be if it was demoted,
2356 // then UpdateIndexAllocation will have an accurate representation of the maximum space
2357 // it can use in the file record. There's still a chance that the act of allocating an
2358 // index node after demoting the index root will increase the size of the file record beyond
2359 // it's limit, but if that happens, an attribute-list will most definitely be needed.
2360 // This a bit hacky, but it seems to be functional.
2361
2362 // Calculate the minimum size of the index root attribute, considering one dummy key and one VCN
2363 MinIndexRootSize.QuadPart = sizeof(INDEX_ROOT_ATTRIBUTE) // size of the index root headers
2364 + 0x18; // Size of dummy key with a VCN for a subnode
2365 ASSERT(MinIndexRootSize.QuadPart % ATTR_RECORD_ALIGNMENT == 0);
2366
2367 // Temporarily shrink the index root to it's minimal size
2368 AttributeLength = MinIndexRootSize.LowPart;
2369 AttributeLength += sizeof(INDEX_ROOT_ATTRIBUTE);
2370
2371
2372 // FIXME: IndexRoot will probably be invalid until we're finished. If we fail before we finish, the directory will probably be toast.
2373 // The potential for catastrophic data-loss exists!!! :)
2374
2375 // Update the length of the attribute in the file record of the parent directory
2377 IndexRootContext,
2378 ParentFileRecord,
2379 IndexRootOffset,
2380 AttributeLength);
2381 if (!NT_SUCCESS(Status))
2382 {
2383 DPRINT1("ERROR: Unable to set length of index root!\n");
2384 DestroyBTree(NewTree);
2385 ReleaseAttributeContext(IndexRootContext);
2386 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2387 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2388 return Status;
2389 }
2390
2391 // Update the index allocation
2392 Status = UpdateIndexAllocation(DeviceExt, NewTree, I30IndexRoot->SizeOfEntry, ParentFileRecord);
2393 if (!NT_SUCCESS(Status))
2394 {
2395 DPRINT1("ERROR: Failed to update index allocation from B-Tree!\n");
2396 DestroyBTree(NewTree);
2397 ReleaseAttributeContext(IndexRootContext);
2398 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2399 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2400 return Status;
2401 }
2402
2403#ifndef NDEBUG
2404 DPRINT1("Index Allocation updated\n");
2405 DumpBTree(NewTree);
2406#endif
2407
2408 // Find the maximum index root size given what the file record can hold
2409 // First, find the max index size assuming index root is the last attribute
2410 NewMaxIndexRootSize =
2411 DeviceExt->NtfsInfo.BytesPerFileRecord // Start with the size of a file record
2412 - IndexRootOffset // Subtract the length of everything that comes before index root
2413 - IndexRootContext->pRecord->Resident.ValueOffset // Subtract the length of the attribute header for index root
2414 - sizeof(INDEX_ROOT_ATTRIBUTE) // Subtract the length of the index root header
2415 - (sizeof(ULONG) * 2); // Subtract the length of the file record end marker and padding
2416
2417 // Are there attributes after this one?
2418 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset + IndexRootContext->pRecord->Length);
2419 if (NextAttribute->Type != AttributeEnd)
2420 {
2421 // Find the length of all attributes after this one, not counting the end marker
2422 ULONG LengthOfAttributes = 0;
2423 PNTFS_ATTR_RECORD CurrentAttribute = NextAttribute;
2424 while (CurrentAttribute->Type != AttributeEnd)
2425 {
2426 LengthOfAttributes += CurrentAttribute->Length;
2427 CurrentAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)CurrentAttribute + CurrentAttribute->Length);
2428 }
2429
2430 // Leave room for the existing attributes
2431 NewMaxIndexRootSize -= LengthOfAttributes;
2432 }
2433
2434 // The index allocation and index bitmap may have grown, leaving less room for the index root,
2435 // so now we need to double-check that index root isn't too large
2436 NodeSize = GetSizeOfIndexEntries(NewTree->RootNode);
2437 if (NodeSize > NewMaxIndexRootSize)
2438 {
2439 DPRINT1("Demoting index root.\nNodeSize: 0x%lx\nNewMaxIndexRootSize: 0x%lx\n", NodeSize, NewMaxIndexRootSize);
2440
2441 Status = DemoteBTreeRoot(NewTree);
2442 if (!NT_SUCCESS(Status))
2443 {
2444 DPRINT1("ERROR: Failed to demote index root!\n");
2445 DestroyBTree(NewTree);
2446 ReleaseAttributeContext(IndexRootContext);
2447 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2448 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2449 return Status;
2450 }
2451
2452 // We need to update the index allocation once more
2453 Status = UpdateIndexAllocation(DeviceExt, NewTree, I30IndexRoot->SizeOfEntry, ParentFileRecord);
2454 if (!NT_SUCCESS(Status))
2455 {
2456 DPRINT1("ERROR: Failed to update index allocation from B-Tree!\n");
2457 DestroyBTree(NewTree);
2458 ReleaseAttributeContext(IndexRootContext);
2459 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2460 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2461 return Status;
2462 }
2463
2464 // re-recalculate max size of index root
2465 NewMaxIndexRootSize =
2466 // Find the maximum index size given what the file record can hold
2467 // First, find the max index size assuming index root is the last attribute
2468 DeviceExt->NtfsInfo.BytesPerFileRecord // Start with the size of a file record
2469 - IndexRootOffset // Subtract the length of everything that comes before index root
2470 - IndexRootContext->pRecord->Resident.ValueOffset // Subtract the length of the attribute header for index root
2471 - sizeof(INDEX_ROOT_ATTRIBUTE) // Subtract the length of the index root header
2472 - (sizeof(ULONG) * 2); // Subtract the length of the file record end marker and padding
2473
2474 // Are there attributes after this one?
2475 NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset + IndexRootContext->pRecord->Length);
2476 if (NextAttribute->Type != AttributeEnd)
2477 {
2478 // Find the length of all attributes after this one, not counting the end marker
2479 ULONG LengthOfAttributes = 0;
2480 PNTFS_ATTR_RECORD CurrentAttribute = NextAttribute;
2481 while (CurrentAttribute->Type != AttributeEnd)
2482 {
2483 LengthOfAttributes += CurrentAttribute->Length;
2484 CurrentAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)CurrentAttribute + CurrentAttribute->Length);
2485 }
2486
2487 // Leave room for the existing attributes
2488 NewMaxIndexRootSize -= LengthOfAttributes;
2489 }
2490
2491
2492 }
2493
2494 // Create the Index Root from the B*Tree
2495 Status = CreateIndexRootFromBTree(DeviceExt, NewTree, NewMaxIndexRootSize, &NewIndexRoot, &BtreeIndexLength);
2496 if (!NT_SUCCESS(Status))
2497 {
2498 DPRINT1("ERROR: Failed to create Index root from B-Tree!\n");
2499 DestroyBTree(NewTree);
2500 ReleaseAttributeContext(IndexRootContext);
2501 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2502 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2503 return Status;
2504 }
2505
2506 // We're done with the B-Tree now
2507 DestroyBTree(NewTree);
2508
2509 // Write back the new index root attribute to the parent directory file record
2510
2511 // First, we need to resize the attribute.
2512 // CreateIndexRootFromBTree() should have verified that the index root fits within MaxIndexSize.
2513 // We can't set the size as we normally would, because $INDEX_ROOT must always be resident.
2514 AttributeLength = NewIndexRoot->Header.AllocatedSize + FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header);
2515
2516 if (AttributeLength != IndexRootContext->pRecord->Resident.ValueLength)
2517 {
2518 // Update the length of the attribute in the file record of the parent directory
2520 IndexRootContext,
2521 ParentFileRecord,
2522 IndexRootOffset,
2523 AttributeLength);
2524 if (!NT_SUCCESS(Status))
2525 {
2526 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
2527 ReleaseAttributeContext(IndexRootContext);
2528 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2529 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2530 DPRINT1("ERROR: Unable to set resident attribute length!\n");
2531 return Status;
2532 }
2533
2534 }
2535
2536 NT_ASSERT(ParentFileRecord->BytesInUse <= DeviceExt->NtfsInfo.BytesPerFileRecord);
2537
2538 Status = UpdateFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
2539 if (!NT_SUCCESS(Status))
2540 {
2541 DPRINT1("ERROR: Failed to update file record of directory with index: %llx\n", DirectoryMftIndex);
2542 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2543 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
2544 ReleaseAttributeContext(IndexRootContext);
2545 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2546 return Status;
2547 }
2548
2549 // Write the new index root to disk
2550 Status = WriteAttribute(DeviceExt,
2551 IndexRootContext,
2552 0,
2553 (PUCHAR)NewIndexRoot,
2554 AttributeLength,
2555 &LengthWritten,
2556 ParentFileRecord);
2557 if (!NT_SUCCESS(Status) || LengthWritten != AttributeLength)
2558 {
2559 DPRINT1("ERROR: Unable to write new index root attribute to parent directory!\n");
2560 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
2561 ReleaseAttributeContext(IndexRootContext);
2562 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2563 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2564 return Status;
2565 }
2566
2567 // re-read the parent file record, so we can dump it
2568 Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
2569 if (!NT_SUCCESS(Status))
2570 {
2571 DPRINT1("ERROR: Couldn't read parent directory after messing with it!\n");
2572 }
2573 else
2574 {
2575#ifndef NDEBUG
2576 DPRINT1("Dumping new B-Tree:\n");
2577
2578 Status = CreateBTreeFromIndex(DeviceExt, ParentFileRecord, IndexRootContext, NewIndexRoot, &NewTree);
2579 if (!NT_SUCCESS(Status))
2580 {
2581 DPRINT1("ERROR: Couldn't re-create b-tree\n");
2582 return Status;
2583 }
2584
2585 DumpBTree(NewTree);
2586
2587 DestroyBTree(NewTree);
2588
2589 NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
2590#endif
2591 }
2592
2593 // Cleanup
2594 ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
2595 ReleaseAttributeContext(IndexRootContext);
2596 ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
2597 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, ParentFileRecord);
2598
2599 return Status;
2600}
2601
2605{
2606 USHORT *pShortToFixUp;
2607 ULONG ArrayEntryCount = Record->UsaCount - 1;
2608 ULONG Offset = Vcb->NtfsInfo.BytesPerSector - 2;
2609 ULONG i;
2610
2611 PFIXUP_ARRAY fixupArray = (PFIXUP_ARRAY)((UCHAR*)Record + Record->UsaOffset);
2612
2613 DPRINT("AddFixupArray(%p, %p)\n fixupArray->USN: %u, ArrayEntryCount: %u\n", Vcb, Record, fixupArray->USN, ArrayEntryCount);
2614
2615 fixupArray->USN++;
2616
2617 for (i = 0; i < ArrayEntryCount; i++)
2618 {
2619 DPRINT("USN: %u\tOffset: %u\n", fixupArray->USN, Offset);
2620
2621 pShortToFixUp = (USHORT*)((PCHAR)Record + Offset);
2622 fixupArray->Array[i] = *pShortToFixUp;
2623 *pShortToFixUp = fixupArray->USN;
2624 Offset += Vcb->NtfsInfo.BytesPerSector;
2625 }
2626
2627 return STATUS_SUCCESS;
2628}
2629
2632 ULONGLONG lcn,
2633 ULONG count,
2634 PVOID buffer)
2635{
2636 LARGE_INTEGER DiskSector;
2637
2638 DiskSector.QuadPart = lcn;
2639
2640 return NtfsReadSectors(Vcb->StorageDevice,
2641 DiskSector.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
2642 count * Vcb->NtfsInfo.SectorsPerCluster,
2643 Vcb->NtfsInfo.BytesPerSector,
2644 buffer,
2645 FALSE);
2646}
2647
2648
2649BOOLEAN
2651 PINDEX_ENTRY_ATTRIBUTE IndexEntry,
2652 BOOLEAN DirSearch,
2653 BOOLEAN CaseSensitive)
2654{
2655 BOOLEAN Ret, Alloc = FALSE;
2656 UNICODE_STRING EntryName;
2657
2658 EntryName.Buffer = IndexEntry->FileName.Name;
2659 EntryName.Length =
2660 EntryName.MaximumLength = IndexEntry->FileName.NameLength * sizeof(WCHAR);
2661
2662 if (DirSearch)
2663 {
2664 UNICODE_STRING IntFileName;
2665 if (!CaseSensitive)
2666 {
2668 Alloc = TRUE;
2669 }
2670 else
2671 {
2672 IntFileName = *FileName;
2673 }
2674
2675 Ret = FsRtlIsNameInExpression(&IntFileName, &EntryName, !CaseSensitive, NULL);
2676
2677 if (Alloc)
2678 {
2679 RtlFreeUnicodeString(&IntFileName);
2680 }
2681
2682 return Ret;
2683 }
2684 else
2685 {
2686 return (RtlCompareUnicodeString(FileName, &EntryName, !CaseSensitive) == 0);
2687 }
2688}
2689
2715{
2716 PFILE_RECORD_HEADER MirrorFileRecord;
2717 PNTFS_ATTR_CONTEXT MirrDataContext;
2718 PNTFS_ATTR_CONTEXT MftDataContext;
2719 PCHAR DataBuffer;
2723 ULONG LengthWritten;
2724
2725 // Allocate memory for the Mft mirror file record
2726 MirrorFileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
2727 if (!MirrorFileRecord)
2728 {
2729 DPRINT1("Error: Failed to allocate memory for $MFTMirr!\n");
2731 }
2732
2733 // Read the Mft Mirror file record
2734 Status = ReadFileRecord(Vcb, NTFS_FILE_MFTMIRR, MirrorFileRecord);
2735 if (!NT_SUCCESS(Status))
2736 {
2737 DPRINT1("ERROR: Failed to read $MFTMirr!\n");
2738 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2739 return Status;
2740 }
2741
2742 // Find the $DATA attribute of $MFTMirr
2743 Status = FindAttribute(Vcb, MirrorFileRecord, AttributeData, L"", 0, &MirrDataContext, NULL);
2744 if (!NT_SUCCESS(Status))
2745 {
2746 DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
2747 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2748 return Status;
2749 }
2750
2751 // Find the $DATA attribute of $MFT
2752 Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeData, L"", 0, &MftDataContext, NULL);
2753 if (!NT_SUCCESS(Status))
2754 {
2755 DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
2756 ReleaseAttributeContext(MirrDataContext);
2757 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2758 return Status;
2759 }
2760
2761 // Get the size of the mirror's $DATA attribute
2762 DataLength = AttributeDataLength(MirrDataContext->pRecord);
2763
2764 ASSERT(DataLength % Vcb->NtfsInfo.BytesPerFileRecord == 0);
2765
2766 // Create buffer for the mirror's $DATA attribute
2768 if (!DataBuffer)
2769 {
2770 DPRINT1("Error: Couldn't allocate memory for $DATA buffer!\n");
2771 ReleaseAttributeContext(MftDataContext);
2772 ReleaseAttributeContext(MirrDataContext);
2773 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2775 }
2776
2778
2779 // Back up the first several entries of the Mft's $DATA Attribute
2780 BytesRead = ReadAttribute(Vcb, MftDataContext, 0, DataBuffer, (ULONG)DataLength);
2781 if (BytesRead != (ULONG)DataLength)
2782 {
2783 DPRINT1("Error: Failed to read $DATA for $MFTMirr!\n");
2784 ReleaseAttributeContext(MftDataContext);
2785 ReleaseAttributeContext(MirrDataContext);
2786 ExFreePoolWithTag(DataBuffer, TAG_NTFS);
2787 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2788 return STATUS_UNSUCCESSFUL;
2789 }
2790
2791 // Write the mirror's $DATA attribute
2793 MirrDataContext,
2794 0,
2795 (PUCHAR)DataBuffer,
2796 DataLength,
2797 &LengthWritten,
2798 MirrorFileRecord);
2799 if (!NT_SUCCESS(Status))
2800 {
2801 DPRINT1("ERROR: Failed to write $DATA attribute of $MFTMirr!\n");
2802 }
2803
2804 // Cleanup
2805 ReleaseAttributeContext(MftDataContext);
2806 ReleaseAttributeContext(MirrDataContext);
2807 ExFreePoolWithTag(DataBuffer, TAG_NTFS);
2808 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MirrorFileRecord);
2809
2810 return Status;
2811}
2812
2813#if 0
2814static
2815VOID
2816DumpIndexEntry(PINDEX_ENTRY_ATTRIBUTE IndexEntry)
2817{
2818 DPRINT1("Entry: %p\n", IndexEntry);
2819 DPRINT1("\tData.Directory.IndexedFile: %I64x\n", IndexEntry->Data.Directory.IndexedFile);
2820 DPRINT1("\tLength: %u\n", IndexEntry->Length);
2821 DPRINT1("\tKeyLength: %u\n", IndexEntry->KeyLength);
2822 DPRINT1("\tFlags: %x\n", IndexEntry->Flags);
2823 DPRINT1("\tReserved: %x\n", IndexEntry->Reserved);
2824 DPRINT1("\t\tDirectoryFileReferenceNumber: %I64x\n", IndexEntry->FileName.DirectoryFileReferenceNumber);
2825 DPRINT1("\t\tCreationTime: %I64u\n", IndexEntry->FileName.CreationTime);
2826 DPRINT1("\t\tChangeTime: %I64u\n", IndexEntry->FileName.ChangeTime);
2827 DPRINT1("\t\tLastWriteTime: %I64u\n", IndexEntry->FileName.LastWriteTime);
2828 DPRINT1("\t\tLastAccessTime: %I64u\n", IndexEntry->FileName.LastAccessTime);
2829 DPRINT1("\t\tAllocatedSize: %I64u\n", IndexEntry->FileName.AllocatedSize);
2830 DPRINT1("\t\tDataSize: %I64u\n", IndexEntry->FileName.DataSize);
2831 DPRINT1("\t\tFileAttributes: %x\n", IndexEntry->FileName.FileAttributes);
2832 DPRINT1("\t\tNameLength: %u\n", IndexEntry->FileName.NameLength);
2833 DPRINT1("\t\tNameType: %x\n", IndexEntry->FileName.NameType);
2834 DPRINT1("\t\tName: %.*S\n", IndexEntry->FileName.NameLength, IndexEntry->FileName.Name);
2835}
2836#endif
2837
2840 PFILE_RECORD_HEADER MftRecord,
2841 ULONG IndexBlockSize,
2843 PNTFS_ATTR_CONTEXT IndexAllocationContext,
2845 ULONGLONG VCN,
2846 PULONG StartEntry,
2847 PULONG CurrentEntry,
2848 BOOLEAN DirSearch,
2849 BOOLEAN CaseSensitive,
2850 ULONGLONG *OutMFTIndex)
2851{
2852 PINDEX_BUFFER IndexRecord;
2855 PINDEX_ENTRY_ATTRIBUTE FirstEntry;
2856 PINDEX_ENTRY_ATTRIBUTE LastEntry;
2857 PINDEX_ENTRY_ATTRIBUTE IndexEntry;
2860
2861 DPRINT("BrowseSubNodeIndexEntries(%p, %p, %lu, %wZ, %p, %p, %I64d, %lu, %lu, %s, %s, %p)\n",
2862 Vcb,
2863 MftRecord,
2864 IndexBlockSize,
2865 FileName,
2866 IndexAllocationContext,
2867 Bitmap,
2868 VCN,
2869 *StartEntry,
2870 *CurrentEntry,
2871 "FALSE",
2872 DirSearch ? "TRUE" : "FALSE",
2873 CaseSensitive ? "TRUE" : "FALSE",
2874 OutMFTIndex);
2875
2876 // Calculate node number as VCN / Clusters per index record
2877 NodeNumber = VCN / (Vcb->NtfsInfo.BytesPerIndexRecord / Vcb->NtfsInfo.BytesPerCluster);
2878
2879 // Is the bit for this node clear in the bitmap?
2881 {
2882 DPRINT1("File system corruption detected, node with VCN %I64u is marked as deleted.\n", VCN);
2883 return STATUS_DATA_ERROR;
2884 }
2885
2886 // Allocate memory for the index record
2887 IndexRecord = ExAllocatePoolWithTag(NonPagedPool, IndexBlockSize, TAG_NTFS);
2888 if (!IndexRecord)
2889 {
2890 DPRINT1("Unable to allocate memory for index record!\n");
2892 }
2893
2894 // Calculate offset of index record
2895 Offset = VCN * Vcb->NtfsInfo.BytesPerCluster;
2896
2897 // Read the index record
2898 BytesRead = ReadAttribute(Vcb, IndexAllocationContext, Offset, (PCHAR)IndexRecord, IndexBlockSize);
2899 if (BytesRead != IndexBlockSize)
2900 {
2901 DPRINT1("Unable to read index record!\n");
2902 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2903 return STATUS_UNSUCCESSFUL;
2904 }
2905
2906 // Assert that we're dealing with an index record here
2907 ASSERT(IndexRecord->Ntfs.Type == NRH_INDX_TYPE);
2908
2909 // Apply the fixup array to the index record
2910 Status = FixupUpdateSequenceArray(Vcb, &((PFILE_RECORD_HEADER)IndexRecord)->Ntfs);
2911 if (!NT_SUCCESS(Status))
2912 {
2913 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2914 DPRINT1("Failed to apply fixup array!\n");
2915 return Status;
2916 }
2917
2918 ASSERT(IndexRecord->Header.AllocatedSize + FIELD_OFFSET(INDEX_BUFFER, Header) == IndexBlockSize);
2919 FirstEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexRecord->Header + IndexRecord->Header.FirstEntryOffset);
2920 LastEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)&IndexRecord->Header + IndexRecord->Header.TotalSizeOfEntries);
2921 ASSERT(LastEntry <= (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexRecord + IndexBlockSize));
2922
2923 // Loop through all Index Entries of index, starting with FirstEntry
2924 IndexEntry = FirstEntry;
2925 while (IndexEntry <= LastEntry)
2926 {
2927 // Does IndexEntry have a sub-node?
2928 if (IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
2929 {
2930 if (!(IndexRecord->Header.Flags & INDEX_NODE_LARGE) || !IndexAllocationContext)
2931 {
2932 DPRINT1("Filesystem corruption detected!\n");
2933 }
2934 else
2935 {
2937 MftRecord,
2938 IndexBlockSize,
2939 FileName,
2940 IndexAllocationContext,
2941 Bitmap,
2942 GetIndexEntryVCN(IndexEntry),
2943 StartEntry,
2944 CurrentEntry,
2945 DirSearch,
2946 CaseSensitive,
2947 OutMFTIndex);
2948 if (NT_SUCCESS(Status))
2949 {
2950 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2951 return Status;
2952 }
2953 }
2954 }
2955
2956 // Are we done?
2957 if (IndexEntry->Flags & NTFS_INDEX_ENTRY_END)
2958 break;
2959
2960 // If we've found a file whose index is greater than or equal to StartEntry that matches the search criteria
2961 if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= NTFS_FILE_FIRST_USER_FILE &&
2962 *CurrentEntry >= *StartEntry &&
2963 IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
2964 CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
2965 {
2966 *StartEntry = *CurrentEntry;
2967 *OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
2968 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2969 return STATUS_SUCCESS;
2970 }
2971
2972 // Advance to the next index entry
2973 (*CurrentEntry) += 1;
2974 ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
2975 IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
2976 }
2977
2978 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
2979
2981}
2982
2985 PFILE_RECORD_HEADER MftRecord,
2986 PINDEX_ROOT_ATTRIBUTE IndexRecord,
2987 ULONG IndexBlockSize,
2988 PINDEX_ENTRY_ATTRIBUTE FirstEntry,
2989 PINDEX_ENTRY_ATTRIBUTE LastEntry,
2991 PULONG StartEntry,
2992 PULONG CurrentEntry,
2993 BOOLEAN DirSearch,
2994 BOOLEAN CaseSensitive,
2995 ULONGLONG *OutMFTIndex)
2996{
2998 PINDEX_ENTRY_ATTRIBUTE IndexEntry;
2999 PNTFS_ATTR_CONTEXT IndexAllocationContext;
3000 PNTFS_ATTR_CONTEXT BitmapContext;
3001 PCHAR *BitmapMem;
3002 ULONG *BitmapPtr;
3004
3005 DPRINT("BrowseIndexEntries(%p, %p, %p, %lu, %p, %p, %wZ, %lu, %lu, %s, %s, %p)\n",
3006 Vcb,
3007 MftRecord,
3008 IndexRecord,
3009 IndexBlockSize,
3010 FirstEntry,
3011 LastEntry,
3012 FileName,
3013 *StartEntry,
3014 *CurrentEntry,
3015 DirSearch ? "TRUE" : "FALSE",
3016 CaseSensitive ? "TRUE" : "FALSE",
3017 OutMFTIndex);
3018
3019 // Find the $I30 index allocation, if there is one
3020 Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationContext, NULL);
3021 if (NT_SUCCESS(Status))
3022 {
3023 ULONGLONG BitmapLength;
3024 // Find the bitmap attribute for the index
3025 Status = FindAttribute(Vcb, MftRecord, AttributeBitmap, L"$I30", 4, &BitmapContext, NULL);
3026 if (!NT_SUCCESS(Status))
3027 {
3028 DPRINT1("Potential file system corruption detected!\n");
3029 ReleaseAttributeContext(IndexAllocationContext);
3030 return Status;
3031 }
3032
3033 // Get the length of the bitmap attribute
3034 BitmapLength = AttributeDataLength(BitmapContext->pRecord);
3035
3036 // Allocate memory for the bitmap, including some padding; RtlInitializeBitmap() wants a pointer
3037 // that's ULONG-aligned, and it wants the size of the memory allocated for it to be a ULONG-multiple.
3038 BitmapMem = ExAllocatePoolWithTag(NonPagedPool, BitmapLength + sizeof(ULONG), TAG_NTFS);
3039 if (!BitmapMem)
3040 {
3041 DPRINT1("Error: failed to allocate bitmap!");
3042 ReleaseAttributeContext(BitmapContext);
3043 ReleaseAttributeContext(IndexAllocationContext);
3045 }
3046
3047 RtlZeroMemory(BitmapMem, BitmapLength + sizeof(ULONG));
3048
3049 // RtlInitializeBitmap() wants a pointer that's ULONG-aligned.
3050 BitmapPtr = (PULONG)ALIGN_UP_BY((ULONG_PTR)BitmapMem, sizeof(ULONG));
3051
3052 // Read the existing bitmap data
3053 Status = ReadAttribute(Vcb, BitmapContext, 0, (PCHAR)BitmapPtr, BitmapLength);
3054 if (!NT_SUCCESS(Status))
3055 {
3056 DPRINT1("ERROR: Failed to read bitmap attribute!\n");
3057 ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3058 ReleaseAttributeContext(BitmapContext);
3059 ReleaseAttributeContext(IndexAllocationContext);
3060 return Status;
3061 }
3062
3063 // Initialize bitmap
3064 RtlInitializeBitMap(&Bitmap, BitmapPtr, BitmapLength * 8);
3065 }
3066 else
3067 {
3068 // Couldn't find an index allocation
3069 IndexAllocationContext = NULL;
3070 }
3071
3072
3073 // Loop through all Index Entries of index, starting with FirstEntry
3074 IndexEntry = FirstEntry;
3075 while (IndexEntry <= LastEntry)
3076 {
3077 // Does IndexEntry have a sub-node?
3078 if (IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
3079 {
3080 if (!(IndexRecord->Header.Flags & INDEX_ROOT_LARGE) || !IndexAllocationContext)
3081 {
3082 DPRINT1("Filesystem corruption detected!\n");
3083 }
3084 else
3085 {
3087 MftRecord,
3088 IndexBlockSize,
3089 FileName,
3090 IndexAllocationContext,
3091 &Bitmap,
3092 GetIndexEntryVCN(IndexEntry),
3093 StartEntry,
3094 CurrentEntry,
3095 DirSearch,
3096 CaseSensitive,
3097 OutMFTIndex);
3098 if (NT_SUCCESS(Status))
3099 {
3100 ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3101 ReleaseAttributeContext(BitmapContext);
3102 ReleaseAttributeContext(IndexAllocationContext);
3103 return Status;
3104 }
3105 }
3106 }
3107
3108 // Are we done?
3109 if (IndexEntry->Flags & NTFS_INDEX_ENTRY_END)
3110 break;
3111
3112 // If we've found a file whose index is greater than or equal to StartEntry that matches the search criteria
3113 if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= NTFS_FILE_FIRST_USER_FILE &&
3114 *CurrentEntry >= *StartEntry &&
3115 IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
3116 CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
3117 {
3118 *StartEntry = *CurrentEntry;
3119 *OutMFTIndex = (IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK);
3120 if (IndexAllocationContext)
3121 {
3122 ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3123 ReleaseAttributeContext(BitmapContext);
3124 ReleaseAttributeContext(IndexAllocationContext);
3125 }
3126 return STATUS_SUCCESS;
3127 }
3128
3129 // Advance to the next index entry
3130 (*CurrentEntry) += 1;
3131 ASSERT(IndexEntry->Length >= sizeof(INDEX_ENTRY_ATTRIBUTE));
3132 IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)IndexEntry + IndexEntry->Length);
3133 }
3134
3135 if (IndexAllocationContext)
3136 {
3137 ExFreePoolWithTag(BitmapMem, TAG_NTFS);
3138 ReleaseAttributeContext(BitmapContext);
3139 ReleaseAttributeContext(IndexAllocationContext);
3140 }
3141
3143}
3144
3147 ULONGLONG MFTIndex,
3149 PULONG FirstEntry,
3150 BOOLEAN DirSearch,
3151 BOOLEAN CaseSensitive,
3152 ULONGLONG *OutMFTIndex)
3153{
3154 PFILE_RECORD_HEADER MftRecord;
3155 PNTFS_ATTR_CONTEXT IndexRootCtx;
3156 PINDEX_ROOT_ATTRIBUTE IndexRoot;
3157 PCHAR IndexRecord;
3158 PINDEX_ENTRY_ATTRIBUTE IndexEntry, IndexEntryEnd;
3160 ULONG CurrentEntry = 0;
3161
3162 DPRINT("NtfsFindMftRecord(%p, %I64d, %wZ, %lu, %s, %s, %p)\n",
3163 Vcb,
3164 MFTIndex,
3165 FileName,
3166 *FirstEntry,
3167 DirSearch ? "TRUE" : "FALSE",
3168 CaseSensitive ? "TRUE" : "FALSE",
3169 OutMFTIndex);
3170
3171 MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
3172 if (MftRecord == NULL)
3173 {
3175 }
3176
3177 Status = ReadFileRecord(Vcb, MFTIndex, MftRecord);
3178 if (!NT_SUCCESS(Status))
3179 {
3180 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3181 return Status;
3182 }
3183
3184 ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
3185 Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
3186 if (!NT_SUCCESS(Status))
3187 {
3188 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3189 return Status;
3190 }
3191
3192 IndexRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerIndexRecord, TAG_NTFS);
3193 if (IndexRecord == NULL)
3194 {
3195 ReleaseAttributeContext(IndexRootCtx);
3196 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3198 }
3199
3200 ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, Vcb->NtfsInfo.BytesPerIndexRecord);
3201 IndexRoot = (PINDEX_ROOT_ATTRIBUTE)IndexRecord;
3202 IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)&IndexRoot->Header + IndexRoot->Header.FirstEntryOffset);
3203 /* Index root is always resident. */
3204 IndexEntryEnd = (PINDEX_ENTRY_ATTRIBUTE)(IndexRecord + IndexRoot->Header.TotalSizeOfEntries);
3205 ReleaseAttributeContext(IndexRootCtx);
3206
3207 DPRINT("IndexRecordSize: %x IndexBlockSize: %x\n", Vcb->NtfsInfo.BytesPerIndexRecord, IndexRoot->SizeOfEntry);
3208
3210 MftRecord,
3211 (PINDEX_ROOT_ATTRIBUTE)IndexRecord,
3212 IndexRoot->SizeOfEntry,
3213 IndexEntry,
3214 IndexEntryEnd,
3215 FileName,
3216 FirstEntry,
3217 &CurrentEntry,
3218 DirSearch,
3219 CaseSensitive,
3220 OutMFTIndex);
3221
3222 ExFreePoolWithTag(IndexRecord, TAG_NTFS);
3223 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
3224
3225 return Status;
3226}
3227
3230 PUNICODE_STRING PathName,
3231 BOOLEAN CaseSensitive,
3232 PFILE_RECORD_HEADER *FileRecord,
3233 PULONGLONG MFTIndex,
3234 ULONGLONG CurrentMFTIndex)
3235{
3236 UNICODE_STRING Current, Remaining;
3238 ULONG FirstEntry = 0;
3239
3240 DPRINT("NtfsLookupFileAt(%p, %wZ, %s, %p, %p, %I64x)\n",
3241 Vcb,
3242 PathName,
3243 CaseSensitive ? "TRUE" : "FALSE",
3244 FileRecord,
3245 MFTIndex,
3246 CurrentMFTIndex);
3247
3248 FsRtlDissectName(*PathName, &Current, &Remaining);
3249
3250 while (Current.Length != 0)
3251 {
3252 DPRINT("Current: %wZ\n", &Current);
3253
3254 Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, &Current, &FirstEntry, FALSE, CaseSensitive, &CurrentMFTIndex);
3255 if (!NT_SUCCESS(Status))
3256 {
3257 return Status;
3258 }
3259
3260 if (Remaining.Length == 0)
3261 break;
3262
3263 FsRtlDissectName(Current, &Current, &Remaining);
3264 }
3265
3266 *FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
3267 if (*FileRecord == NULL)
3268 {
3269 DPRINT("NtfsLookupFileAt: Can't allocate MFT record\n");
3271 }
3272
3273 Status = ReadFileRecord(Vcb, CurrentMFTIndex, *FileRecord);
3274 if (!NT_SUCCESS(Status))
3275 {
3276 DPRINT("NtfsLookupFileAt: Can't read MFT record\n");
3277 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, *FileRecord);
3278 return Status;
3279 }
3280
3281 *MFTIndex = CurrentMFTIndex;
3282
3283 return STATUS_SUCCESS;
3284}
3285
3288 PUNICODE_STRING PathName,
3289 BOOLEAN CaseSensitive,
3290 PFILE_RECORD_HEADER *FileRecord,
3291 PULONGLONG MFTIndex)
3292{
3293 return NtfsLookupFileAt(Vcb, PathName, CaseSensitive, FileRecord, MFTIndex, NTFS_FILE_ROOT);
3294}
3295
3296void
3298{
3299 ULONG i, j;
3300
3301 // dump binary data, 8 bytes at a time
3302 for (i = 0; i < Length; i += 8)
3303 {
3304 // display current offset, in hex
3305 DbgPrint("\t%03x\t", i);
3306
3307 // display hex value of each of the next 8 bytes
3308 for (j = 0; j < 8; j++)
3309 DbgPrint("%02x ", *(PUCHAR)(Buffer + i + j));
3310 DbgPrint("\n");
3311 }
3312}
3313
3333VOID
3335 PFILE_RECORD_HEADER FileRecord)
3336{
3337 ULONG i, j;
3338
3339 // dump binary data, 8 bytes at a time
3340 for (i = 0; i < FileRecord->BytesInUse; i += 8)
3341 {
3342 // display current offset, in hex
3343 DbgPrint("\t%03x\t", i);
3344
3345 // display hex value of each of the next 8 bytes
3346 for (j = 0; j < 8; j++)
3347 DbgPrint("%02x ", *(PUCHAR)((ULONG_PTR)FileRecord + i + j));
3348 DbgPrint("\n");
3349 }
3350
3351 NtfsDumpFileAttributes(Vcb, FileRecord);
3352}
3353
3356 PUNICODE_STRING SearchPattern,
3357 PULONG FirstEntry,
3358 PFILE_RECORD_HEADER *FileRecord,
3359 PULONGLONG MFTIndex,
3360 ULONGLONG CurrentMFTIndex,
3361 BOOLEAN CaseSensitive)
3362{
3364
3365 DPRINT("NtfsFindFileAt(%p, %wZ, %lu, %p, %p, %I64x, %s)\n",
3366 Vcb,
3367 SearchPattern,
3368 *FirstEntry,
3369 FileRecord,
3370 MFTIndex,
3371 CurrentMFTIndex,
3372 (CaseSensitive ? "TRUE" : "FALSE"));
3373
3374 Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, SearchPattern, FirstEntry, TRUE, CaseSensitive, &CurrentMFTIndex);
3375 if (!NT_SUCCESS(Status))
3376 {
3377 DPRINT("NtfsFindFileAt: NtfsFindMftRecord() failed with status 0x%08lx\n", Status);
3378 return Status;
3379 }
3380
3381 *FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
3382 if (*FileRecord == NULL)
3383 {
3384 DPRINT("NtfsFindFileAt: Can't allocate MFT record\n");
3386 }
3387
3388 Status = ReadFileRecord(Vcb, CurrentMFTIndex, *FileRecord);
3389 if (!NT_SUCCESS(Status))
3390 {
3391 DPRINT("NtfsFindFileAt: Can't read MFT record\n");
3392 ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, *FileRecord);
3393 return Status;
3394 }
3395
3396 *MFTIndex = CurrentMFTIndex;
3397
3398 return STATUS_SUCCESS;
3399}
3400
3401/* EOF */
ULONG ReadLength
ULONG WriteLength
Definition: CcPinRead_drv.c:40
#define ALIGN_UP_BY(size, align)
unsigned char BOOLEAN
Type
Definition: Type.h:7
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
struct NTFS_ATTR_RECORD * PNTFS_ATTR_RECORD
#define NTFS_FILE_NAME_DOS
Definition: ntfs.h:65
#define NTFS_INDEX_ENTRY_NODE
Definition: ntfs.h:60
#define NTFS_MFT_MASK
Definition: ntfs.h:68
#define NTFS_FILE_ROOT
Definition: ntfs.h:28
#define NTFS_INDEX_ENTRY_END
Definition: ntfs.h:61
#define NTFS_FILE_MFTMIRR
Definition: ntfs.h:24
NTSTATUS CreateBTreeFromIndex(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecordWithIndex, PNTFS_ATTR_CONTEXT IndexRootContext, PINDEX_ROOT_ATTRIBUTE IndexRoot, PB_TREE *NewTree)
Definition: btree.c:682
ULONGLONG GetIndexEntryVCN(PINDEX_ENTRY_ATTRIBUTE IndexEntry)
Definition: btree.c:1641
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
NTSTATUS UpdateIndexAllocation(PDEVICE_EXTENSION DeviceExt, PB_TREE Tree, ULONG IndexBufferSize, PFILE_RECORD_HEADER FileRecord)
Definition: btree.c:1182
VOID DestroyBTree(PB_TREE Tree)
Definition: btree.c:1542
NTSTATUS DemoteBTreeRoot(PB_TREE Tree)
Definition: btree.c:1089
ULONG GetSizeOfIndexEntries(PB_TREE_FILENAME_NODE Node)
Definition: btree.c:855
VOID DumpBTree(PB_TREE Tree)
Definition: btree.c:1622
NTSTATUS CreateIndexRootFromBTree(PDEVICE_EXTENSION DeviceExt, PB_TREE Tree, ULONG MaxIndexSize, PINDEX_ROOT_ATTRIBUTE *IndexRoot, ULONG *Length)
Definition: btree.c:910
return Found
Definition: dirsup.c:1270
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:291
_In_ PFCB Fcb
Definition: cdprocs.h:159
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1444
Definition: bufpool.h:45
Definition: Header.h:9
#define STATUS_PENDING
Definition: d3dkmdt.h:43
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
#define RtlInitializeBitMap
Definition: dbgbitmap.h:326
#define RtlFindClearBitsAndSet
Definition: dbgbitmap.h:333
#define RtlCheckBit
Definition: dbgbitmap.h:349
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
static const WCHAR Cleanup[]
Definition: register.c:80
NTSTATUS AddRun(PNTFS_VCB Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, ULONGLONG NextAssignedCluster, ULONG RunLength)
Definition: attrib.c:599
PUCHAR DecodeRun(PUCHAR DataRun, LONGLONG *DataRunOffset, ULONGLONG *DataRunLength)
Definition: attrib.c:966
NTSTATUS ConvertDataRunsToLargeMCB(PUCHAR DataRun, PLARGE_MCB DataRunsMCB, PULONGLONG pNextVBN)
Definition: attrib.c:825
NTSTATUS FindFirstAttribute(PFIND_ATTR_CONTXT Context, PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord, BOOLEAN OnlyResident, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1383
NTSTATUS FindFirstAttributeListItem(PFIND_ATTR_CONTXT Context, PNTFS_ATTRIBUTE_LIST_ITEM *Item)
Definition: attrib.c:1307
NTSTATUS FreeClusters(PNTFS_VCB Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, ULONG ClustersToFree)
Definition: attrib.c:1057
VOID FindCloseAttribute(PFIND_ATTR_CONTXT Context)
Definition: attrib.c:1465
NTSTATUS ConvertLargeMCBToDataRuns(PLARGE_MCB DataRunsMCB, PUCHAR RunBuffer, ULONG MaxBufferSize, PULONG UsedBufferSize)
Definition: attrib.c:896
VOID NtfsDumpFileAttributes(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
Definition: attrib.c:1790
NTSTATUS FindNextAttribute(PFIND_ATTR_CONTXT Context, PNTFS_ATTR_RECORD *Attribute)
Definition: attrib.c:1431
NTSTATUS FindNextAttributeListItem(PFIND_ATTR_CONTXT Context, PNTFS_ATTRIBUTE_LIST_ITEM *Item)
Definition: attrib.c:1321
PFILE_RECORD_HEADER NtfsCreateEmptyFileRecord(PDEVICE_EXTENSION DeviceExt)
Definition: create.c:818
PNTFS_GLOBAL_DATA NtfsGlobalData
Definition: ntfs.c:36
struct FIXUP_ARRAY * PFIXUP_ARRAY
struct INDEX_BUFFER * PINDEX_BUFFER
#define NRH_FILE_TYPE
Definition: ntfs.h:246
struct INDEX_ENTRY_ATTRIBUTE * PINDEX_ENTRY_ATTRIBUTE
#define NTFS_FILE_FIRST_USER_FILE
Definition: ntfs.h:196
#define INDEX_NODE_LARGE
Definition: ntfs.h:212
#define INDEX_ROOT_LARGE
Definition: ntfs.h:209
#define NRH_INDX_TYPE
Definition: ntfs.h:247
struct INDEX_ROOT_ATTRIBUTE * PINDEX_ROOT_ATTRIBUTE
#define FILE_RECORD_END
Definition: ntfs.h:182
@ AttributeEnd
Definition: ntfs.h:177
@ AttributeIndexRoot
Definition: ntfs.h:169
@ AttributeIndexAllocation
Definition: ntfs.h:170
@ AttributeData
Definition: ntfs.h:168
@ AttributeBitmap
Definition: ntfs.h:171
#define TAG_NTFS
Definition: ntfs.h:12
#define ATTR_RECORD_ALIGNMENT
Definition: ntfs.h:320
NTSTATUS NtfsAllocateClusters(PDEVICE_EXTENSION DeviceExt, ULONG FirstDesiredCluster, ULONG DesiredClusters, PULONG FirstAssignedCluster, PULONG AssignedClusters)
Definition: volinfo.c:105
#define ULONG_PTR
Definition: config.h:101
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
#define NonPagedPool
Definition: env_spec_w32.h:307
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
IN PFCB IN PFILE_OBJECT FileObject IN ULONG AllocationSize
Definition: fatprocs.h:323
struct _FileName FileName
Definition: fatprocs.h:897
VOID NTAPI CcSetFileSizes(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes)
Definition: fssup.c:356
Status
Definition: gdiplustypes.h:25
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint buffer
Definition: glext.h:5915
GLuint index
Definition: glext.h:6031
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
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 DbgPrint
Definition: hal.h:12
static ULONG BitmapBuffer[(XMS_BLOCKS+31)/32]
Definition: himem.c:86
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define ULONG_MAX
Definition: intsafe.h:155
VOID NTAPI FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:1096
VOID NTAPI FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb, IN POOL_TYPE PoolType)
Definition: largemcb.c:451
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:560
NTSTATUS BrowseSubNodeIndexEntries(PNTFS_VCB Vcb, PFILE_RECORD_HEADER MftRecord, ULONG IndexBlockSize, PUNICODE_STRING FileName, PNTFS_ATTR_CONTEXT IndexAllocationContext, PRTL_BITMAP Bitmap, ULONGLONG VCN, PULONG StartEntry, PULONG CurrentEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
Definition: mft.c:2839
void NtfsDumpData(ULONG_PTR Buffer, ULONG Length)
Definition: mft.c:3297
NTSTATUS ReadFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG index, PFILE_RECORD_HEADER file)
Definition: mft.c:1631
NTSTATUS NtfsLookupFileAt(PDEVICE_EXTENSION Vcb, PUNICODE_STRING PathName, BOOLEAN CaseSensitive, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex, ULONGLONG CurrentMFTIndex)
Definition: mft.c:3229
NTSTATUS UpdateFileRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MftIndex, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1931
NTSTATUS NtfsLookupFile(PDEVICE_EXTENSION Vcb, PUNICODE_STRING PathName, BOOLEAN CaseSensitive, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex)
Definition: mft.c:3287
VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
Definition: mft.c:104
NTSTATUS UpdateFileNameRecord(PDEVICE_EXTENSION Vcb, ULONGLONG ParentMFTIndex, PUNICODE_STRING FileName, BOOLEAN DirSearch, ULONGLONG NewDataSize, ULONGLONG NewAllocationSize, BOOLEAN CaseSensitive)
Definition: mft.c:1660
NTSTATUS UpdateMftMirror(PNTFS_VCB Vcb)
Definition: mft.c:2714
PNTFS_ATTR_CONTEXT PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:41
ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:259
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 ReadAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, PCHAR Buffer, ULONG Length)
Definition: mft.c:1065
NTSTATUS WriteAttribute(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT Context, ULONGLONG Offset, const PUCHAR Buffer, ULONG Length, PULONG RealLengthWritten, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:1315
NTSTATUS BrowseIndexEntries(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER MftRecord, PINDEX_ROOT_ATTRIBUTE IndexRecord, ULONG IndexBlockSize, PINDEX_ENTRY_ATTRIBUTE FirstEntry, PINDEX_ENTRY_ATTRIBUTE LastEntry, PUNICODE_STRING FileName, PULONG StartEntry, PULONG CurrentEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
Definition: mft.c:2984
VOID SetFileRecordEnd(PFILE_RECORD_HEADER FileRecord, PNTFS_ATTR_RECORD AttrEnd, ULONG EndMarker)
Definition: mft.c:706
NTSTATUS IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
Definition: mft.c:293
NTSTATUS AddFixupArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:2603
NTSTATUS SetNonResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:756
PNTFS_ATTR_RECORD MoveAttributes(PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_RECORD FirstAttributeToMove, ULONG FirstAttributeOffset, ULONG_PTR MoveTo)
Definition: mft.c:512
NTSTATUS NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt, ULONGLONG DirectoryMftIndex, ULONGLONG FileReferenceNumber, PFILENAME_ATTRIBUTE FilenameAttribute, BOOLEAN CaseSensitive)
Definition: mft.c:2192
NTSTATUS UpdateIndexEntryFileNameSize(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER MftRecord, PCHAR IndexRecord, ULONG IndexBlockSize, PINDEX_ENTRY_ATTRIBUTE FirstEntry, PINDEX_ENTRY_ATTRIBUTE LastEntry, PUNICODE_STRING FileName, PULONG StartEntry, PULONG CurrentEntry, BOOLEAN DirSearch, ULONGLONG NewDataSize, ULONGLONG NewAllocatedSize, BOOLEAN CaseSensitive)
Definition: mft.c:1770
ULONGLONG AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord)
Definition: mft.c:249
NTSTATUS AddNewMftEntry(PFILE_RECORD_HEADER FileRecord, PDEVICE_EXTENSION DeviceExt, PULONGLONG DestinationIndex, BOOLEAN CanWait)
Definition: mft.c:2022
VOID NtfsDumpFileRecord(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord)
Definition: mft.c:3334
NTSTATUS SetResidentAttributeDataLength(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:891
NTSTATUS NtfsFindMftRecord(PDEVICE_EXTENSION Vcb, ULONGLONG MFTIndex, PUNICODE_STRING FileName, PULONG FirstEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive, ULONGLONG *OutMFTIndex)
Definition: mft.c:3146
NTSTATUS ReadLCN(PDEVICE_EXTENSION Vcb, ULONGLONG lcn, ULONG count, PVOID buffer)
Definition: mft.c:2631
NTSTATUS FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb, PNTFS_RECORD_HEADER Record)
Definition: mft.c:1965
NTSTATUS InternalSetResidentAttributeLength(PDEVICE_EXTENSION DeviceExt, PNTFS_ATTR_CONTEXT AttrContext, PFILE_RECORD_HEADER FileRecord, ULONG AttrOffset, ULONG DataSize)
Definition: mft.c:542
NTSTATUS NtfsFindFileAt(PDEVICE_EXTENSION Vcb, PUNICODE_STRING SearchPattern, PULONG FirstEntry, PFILE_RECORD_HEADER *FileRecord, PULONGLONG MFTIndex, ULONGLONG CurrentMFTIndex, BOOLEAN CaseSensitive)
Definition: mft.c:3355
BOOLEAN CompareFileName(PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch, BOOLEAN CaseSensitive)
Definition: mft.c:2650
NTSTATUS SetAttributeDataLength(PFILE_OBJECT FileObject, PNTFS_FCB Fcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, PLARGE_INTEGER DataSize)
Definition: mft.c:615
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
#define min(a, b)
Definition: monoChain.cc:55
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4755
_In_ PUNICODE_STRING _Inout_ PUNICODE_STRING Destination
Definition: rtlfuncs.h:3016
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:391
__GNU_EXTENSION typedef __int64 * PLONGLONG
Definition: ntbasedef.h:390
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTATUS NtfsWriteDisk(IN PDEVICE_OBJECT DeviceObject, IN LONGLONG StartingOffset, IN ULONG Length, IN ULONG SectorSize, IN const PUCHAR Buffer)
Definition: blockdev.c:163
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
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
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
BOOLEAN NTAPI FsRtlIsNameInExpression(IN PUNICODE_STRING Expression, IN PUNICODE_STRING Name, IN BOOLEAN IgnoreCase, IN PWCHAR UpcaseTable OPTIONAL)
Definition: name.c:514
VOID NTAPI FsRtlDissectName(IN UNICODE_STRING Name, OUT PUNICODE_STRING FirstPart, OUT PUNICODE_STRING RemainingPart)
Definition: name.c:398
#define STATUS_CANT_WAIT
Definition: ntstatus.h:452
#define STATUS_USER_MAPPED_FILE
Definition: ntstatus.h:711
#define STATUS_PARTIAL_COPY
Definition: ntstatus.h:193
#define STATUS_DATA_ERROR
Definition: ntstatus.h:298
#define L(x)
Definition: ntvdm.h:50
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
#define Vcb
Definition: cdprocs.h:1415
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:66
#define _SEH2_END
Definition: pseh2_64.h:155
#define _SEH2_TRY
Definition: pseh2_64.h:55
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:168
BOOLEAN NTAPI MmCanFileBeTruncated(_In_ PSECTION_OBJECT_POINTERS SectionObjectPointer, _In_opt_ PLARGE_INTEGER NewFileSize)
Definition: section.c:4260
#define STATUS_END_OF_FILE
Definition: shellext.h:67
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
Definition: ntfs.h:454
PB_TREE_FILENAME_NODE RootNode
Definition: ntfs.h:455
ULONGLONG LastWriteTime
Definition: ntfs.h:363
UCHAR NameLength
Definition: ntfs.h:377
ULONGLONG DirectoryFileReferenceNumber
Definition: ntfs.h:360
ULONGLONG DataSize
Definition: ntfs.h:366
UCHAR NameType
Definition: ntfs.h:378
ULONGLONG AllocatedSize
Definition: ntfs.h:365
ULONG FileAttributes
Definition: ntfs.h:367
ULONGLONG LastAccessTime
Definition: ntfs.h:364
ULONGLONG CreationTime
Definition: ntfs.h:361
WCHAR Name[1]
Definition: ntfs.h:379
ULONGLONG ChangeTime
Definition: ntfs.h:362
USHORT Array[]
Definition: ntfs.h:562
USHORT USN
Definition: ntfs.h:561
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:405
NTFS_RECORD_HEADER Ntfs
Definition: ntfs.h:403
Definition: ntfs.h:409
struct INDEX_ENTRY_ATTRIBUTE::@774::@775 Directory
FILENAME_ATTRIBUTE FileName
Definition: ntfs.h:427
USHORT Length
Definition: ntfs.h:423
USHORT KeyLength
Definition: ntfs.h:424
ULONG Reserved
Definition: ntfs.h:420
union INDEX_ENTRY_ATTRIBUTE::@774 Data
USHORT Flags
Definition: ntfs.h:425
ULONG FirstEntryOffset
Definition: ntfs.h:384
ULONG TotalSizeOfEntries
Definition: ntfs.h:385
INDEX_HEADER_ATTRIBUTE Header
Definition: ntfs.h:398
ULONG SizeOfEntry
Definition: ntfs.h:395
ULONGLONG MFTIndex
Definition: ntfs.h:314
ULONG ValueLength
Definition: ntfs.h:138
struct NTFS_ATTR_RECORD::@169::@171 Resident
ULONG Length
Definition: ntfs.h:127
USHORT NameOffset
Definition: ntfs.h:130
UCHAR NameLength
Definition: ntfs.h:129
UCHAR IsNonResident
Definition: ntfs.h:128
ULONG Type
Definition: ntfs.h:126
struct NTFS_ATTR_RECORD::@169::@172 NonResident
BOOLEAN EnableWriteSupport
Definition: ntfs.h:155
NPAGED_LOOKASIDE_LIST AttrCtxtLookasideList
Definition: ntfs.h:154
Definition: cdstruc.h:902
PVCB Vcb
Definition: cdstruc.h:933
FSRTL_COMMON_FCB_HEADER RFCB
Definition: ntfs.h:517
ULONGLONG MFTIndex
Definition: ntfs.h:539
USHORT Flags
Definition: ntfs.h:256
NTFS_RECORD_HEADER Ntfs
Definition: ntfs.h:252
ULONG MFTRecordNumber
Definition: ntfs.h:262
ULONG BytesInUse
Definition: ntfs.h:257
LARGE_INTEGER AllocationSize
Definition: env_spec_w32.h:755
LARGE_INTEGER ValidDataLength
Definition: env_spec_w32.h:757
USHORT MaximumLength
Definition: env_spec_w32.h:370
Definition: fci.c:127
#define max(a, b)
Definition: svc.c:63
uint32_t * PULONG
Definition: typedefs.h:59
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
int64_t LONGLONG
Definition: typedefs.h:68
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
uint16_t * PWCHAR
Definition: typedefs.h:56
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
char * PCHAR
Definition: typedefs.h:51
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
LONGLONG QuadPart
Definition: typedefs.h:114
struct _LARGE_INTEGER::@2304 u
ULONG LowPart
Definition: typedefs.h:106
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:960
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870
_Out_ PUSHORT NodeNumber
Definition: iofuncs.h:2574
* PFILE_OBJECT
Definition: iotypes.h:1998
_In_ struct _KBUGCHECK_REASON_CALLBACK_RECORD * Record
Definition: ketypes.h:268
#define NT_ASSERT
Definition: rtlfuncs.h:3327
#define NT_VERIFY(exp)
Definition: rtlfuncs.h:3304
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180