OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
Index.c
Go to the documentation of this file.
1
9#include "NTFS.h"
10#include "Helper.h"
11
12STATIC UINT64 mBufferSize;
13STATIC UINT8 mDaysPerMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0 };
15
16STATIC
17VOID
19 IN OUT NTFS_FILE *Node OPTIONAL,
20 IN FSHELP_CTX *Context
21 )
22{
23 ASSERT (Context != NULL);
24
25 if ((Node != NULL) && (Node != Context->RootNode)) {
26 FreeFile (Node);
27 FreePool (Node);
28 }
29}
30
31STATIC
32VOID
34 IN OUT FSHELP_CTX *Context
35 )
36{
37 STACK_ELEMENT *Element;
38
39 ASSERT (Context != NULL);
40
41 Element = Context->CurrentNode;
42 if (Element != NULL) {
43 Context->CurrentNode = Element->Parent;
44 FreeNode (Element->Node, Context);
45 FreePool (Element);
46 }
47}
48
49STATIC
50VOID
52 IN OUT FSHELP_CTX *Context
53 )
54{
55 ASSERT (Context != NULL);
56
57 while (Context->CurrentNode != NULL) {
58 PopElement (Context);
59 }
60}
61
62STATIC
63VOID
65 IN OUT FSHELP_CTX *Context
66 )
67{
68 ASSERT (Context != NULL);
69
70 if (Context->CurrentNode->Parent == NULL) {
71 return;
72 }
73
74 PopElement (Context);
75}
76
77STATIC
78EFI_STATUS
80 IN OUT FSHELP_CTX *Context,
81 IN NTFS_FILE *Node,
82 IN FSHELP_FILETYPE FileType
83 )
84{
85 STACK_ELEMENT *Next;
86
87 ASSERT (Context != NULL);
88 ASSERT (Node != NULL);
89
90 Next = AllocateZeroPool (sizeof (*Next));
91 if (Next == NULL) {
92 return EFI_OUT_OF_RESOURCES;
93 }
94
95 Next->Node = Node;
96 Next->Type = FileType & ~FSHELP_CASE_INSENSITIVE;
97 Next->Parent = Context->CurrentNode;
98 Context->CurrentNode = Next;
99
100 return EFI_SUCCESS;
101}
102
103STATIC
104EFI_STATUS
106 IN OUT FSHELP_CTX *Context
107 )
108{
109 ASSERT (Context != NULL);
110
111 FreeStack (Context);
112 return PushNode (Context, Context->RootNode, FSHELP_DIR);
113}
114
115STATIC
116EFI_STATUS
118 IN CHAR16 *Name,
119 IN FSHELP_FILETYPE FileType,
120 IN NTFS_FILE *Node,
121 IN FSHELP_ITER_CTX *Context
122 )
123{
124 INTN Result;
125
126 ASSERT (Name != NULL);
127 ASSERT (Node != NULL);
128 ASSERT (Context != NULL);
129
130 if (FileType == FSHELP_UNKNOWN) {
131 FreePool (Node);
132 return EFI_NOT_FOUND;
133 }
134
135 if ((FileType & FSHELP_CASE_INSENSITIVE) != 0) {
136 Result = OcStriCmp (Context->Name, Name);
137 } else {
138 Result = StrCmp (Context->Name, Name);
139 }
140
141 if (Result != 0) {
142 FreePool (Node);
143 return EFI_NOT_FOUND;
144 }
145
146 *Context->FoundNode = Node;
147 *Context->FoundType = FileType;
148
149 return EFI_SUCCESS;
150}
151
152STATIC
153EFI_STATUS
155 IN CHAR16 *Name,
156 IN FSHELP_FILETYPE FileType,
157 IN NTFS_FILE *Node,
158 IN OUT EFI_FILE_INFO *Info
159 )
160{
161 EFI_STATUS Status;
162
163 ASSERT (Name != NULL);
164 ASSERT (Node != NULL);
165 ASSERT (Info != NULL);
166
167 if ( (Name[0] == L'.')
168 && ((Name[1] == 0) || ( (Name[1] == L'.')
169 && (Name[2] == 0))))
170 {
171 FreeFile (Node);
172 return EFI_NOT_FOUND;
173 }
174
175 if ((mIndexCounter)-- != 0) {
176 FreeFile (Node);
177 return EFI_NOT_FOUND;
178 }
179
180 Status = StrnCpyS (
181 Info->FileName,
182 MAX_PATH,
183 Name,
184 (UINTN)((Info->Size - sizeof (*Info)) / sizeof (CHAR16))
185 );
186 if (EFI_ERROR (Status)) {
187 DEBUG ((DEBUG_INFO, "NTFS: Could not copy string.\n"));
188 FreeFile (Node);
189 return Status;
190 }
191
192 Info->Size = sizeof (*Info) + StrnLenS (Info->FileName, MAX_PATH) * sizeof (CHAR16);
193
194 NtfsToEfiTime (&Info->CreateTime, Node->CreationTime);
195 NtfsToEfiTime (&Info->LastAccessTime, Node->ReadTime);
196 NtfsToEfiTime (&Info->ModificationTime, Node->AlteredTime);
197
198 Info->Attribute = EFI_FILE_READ_ONLY;
199 if ((FileType & FSHELP_TYPE_MASK) == FSHELP_DIR) {
200 Info->Attribute |= EFI_FILE_DIRECTORY;
201 }
202
203 FreeFile (Node);
204
205 return EFI_SUCCESS;
206}
207
208STATIC
209EFI_STATUS
211 IN CHAR16 *FileName,
212 IN FSHELP_FILETYPE FileType,
213 IN NTFS_FILE *Node,
214 IN EFI_NTFS_FILE *File
215 )
216{
217 ASSERT (FileName != NULL);
218 ASSERT (Node != NULL);
219 ASSERT (File != NULL);
220
221 if (StrCmp (FileName, File->BaseName) != 0) {
222 FreeFile (Node);
223 return EFI_NOT_FOUND;
224 }
225
226 File->IsDir = (BOOLEAN)((FileType & FSHELP_TYPE_MASK) == FSHELP_DIR);
227 FreeFile (Node);
228
229 return EFI_SUCCESS;
230}
231
232STATIC
233EFI_STATUS
235 IN NTFS_FILE *Dir,
236 IN UINT8 *Position,
237 OUT VOID *FileOrCtx,
238 IN FUNCTION_TYPE FunctionType
239 )
240{
241 EFI_STATUS Status;
242 CHAR16 *Filename;
243 FSHELP_FILETYPE Type;
244 NTFS_FILE *DirFile;
245 INDEX_ENTRY *IndexEntry;
246 ATTR_FILE_NAME *AttrFileName;
247
248 ASSERT (Dir != NULL);
249 ASSERT (Position != NULL);
250 ASSERT (FileOrCtx != NULL);
251
252 IndexEntry = (INDEX_ENTRY *)Position;
253
254 while (TRUE) {
255 if (mBufferSize < sizeof (*IndexEntry)) {
256 DEBUG ((DEBUG_INFO, "NTFS: (ListFile #1) INDEX_ENTRY is corrupted.\n"));
257 return EFI_VOLUME_CORRUPTED;
258 }
259
260 if ((IndexEntry->Flags & LAST_INDEX_ENTRY) != 0) {
261 break;
262 }
263
264 if (mBufferSize < (sizeof (*IndexEntry) + sizeof (*AttrFileName))) {
265 DEBUG ((DEBUG_INFO, "NTFS: (ListFile #2) INDEX_ENTRY is corrupted.\n"));
266 return EFI_VOLUME_CORRUPTED;
267 }
268
269 AttrFileName = (ATTR_FILE_NAME *)((UINT8 *)IndexEntry + sizeof (*IndexEntry));
270
271 //
272 // Ignore files in DOS namespace, as they will reappear as Win32 names.
273 //
274 if ((AttrFileName->FilenameLen != 0) && (AttrFileName->Namespace != DOS)) {
275 if ((AttrFileName->Flags & ATTR_REPARSE) != 0) {
276 Type = FSHELP_SYMLINK;
277 } else if ((AttrFileName->Flags & ATTR_DIRECTORY) != 0) {
278 Type = FSHELP_DIR;
279 } else {
280 Type = FSHELP_REG;
281 }
282
283 DirFile = AllocateZeroPool (sizeof (*DirFile));
284 if (DirFile == NULL) {
285 DEBUG ((DEBUG_INFO, "NTFS: Could not allocate space for DirFile\n"));
286 return EFI_OUT_OF_RESOURCES;
287 }
288
289 DirFile->File = Dir->File;
290 CopyMem (&DirFile->Inode, IndexEntry->FileRecordNumber, 6U);
291 DirFile->CreationTime = AttrFileName->CreationTime;
292 DirFile->AlteredTime = AttrFileName->AlteredTime;
293 DirFile->ReadTime = AttrFileName->ReadTime;
294
295 if (mBufferSize < (sizeof (*IndexEntry) + sizeof (*AttrFileName) + AttrFileName->FilenameLen * sizeof (CHAR16))) {
296 DEBUG ((DEBUG_INFO, "NTFS: (ListFile #3) INDEX_ENTRY is corrupted.\n"));
297 FreePool (DirFile);
298 return EFI_VOLUME_CORRUPTED;
299 }
300
301 Filename = AllocateZeroPool ((AttrFileName->FilenameLen + 1U) * sizeof (CHAR16));
302 if (Filename == NULL) {
303 DEBUG ((DEBUG_INFO, "NTFS: Failed to allocate buffer for Filename\n"));
304 FreePool (DirFile);
305 return EFI_OUT_OF_RESOURCES;
306 }
307
308 CopyMem (
309 Filename,
310 (UINT8 *)AttrFileName + sizeof (*AttrFileName),
311 AttrFileName->FilenameLen * sizeof (CHAR16)
312 );
313
314 if (AttrFileName->Namespace != POSIX) {
316 }
317
318 switch (FunctionType) {
319 case INFO_HOOK:
320 Status = NtfsDirIter (Filename, Type, DirFile, FileOrCtx);
321 FreePool (DirFile);
322 break;
323 case DIR_HOOK:
324 Status = NtfsDirHook (Filename, Type, DirFile, FileOrCtx);
325 FreePool (DirFile);
326 break;
327 case FILE_ITER:
328 Status = FindFileIter (Filename, Type, DirFile, FileOrCtx);
329 break;
330 default:
331 FreePool (Filename);
332 FreePool (DirFile);
333 return EFI_INVALID_PARAMETER;
334 }
335
336 FreePool (Filename);
337
338 if (Status == EFI_SUCCESS) {
339 return EFI_SUCCESS;
340 }
341 }
342
343 if ( (mBufferSize < IndexEntry->IndexEntryLength)
344 || (IndexEntry->IndexEntryLength == 0))
345 {
346 DEBUG ((DEBUG_INFO, "NTFS: (ListFile #4) INDEX_ENTRY is corrupted.\n"));
347 return EFI_VOLUME_CORRUPTED;
348 }
349
350 mBufferSize -= IndexEntry->IndexEntryLength;
351 IndexEntry = (INDEX_ENTRY *)((UINT8 *)IndexEntry + IndexEntry->IndexEntryLength);
352 }
353
354 return EFI_NOT_FOUND;
355}
356
357STATIC
358EFI_STATUS
360 IN CHAR16 *CurrentPath,
361 IN FSHELP_CTX *Context
362 )
363{
364 EFI_STATUS Status;
365 CHAR16 *Name;
366 CHAR16 *Next;
367 NTFS_FILE *FoundNode;
368 FSHELP_FILETYPE FoundType;
369 FSHELP_ITER_CTX IterCtx;
370 CHAR16 *Symlink;
371 CHAR16 *PathPart;
372
373 ASSERT (CurrentPath != NULL);
374 ASSERT (Context != NULL);
375
376 for (Name = CurrentPath; ; Name = Next) {
377 FoundNode = NULL;
378 FoundType = FSHELP_UNKNOWN;
379
380 while (*Name == L'/') {
381 ++Name;
382 }
383
384 if (*Name == L'\0') {
385 return EFI_SUCCESS;
386 }
387
388 for (Next = Name; (*Next != L'\0') && (*Next != L'/'); ++Next) {
389 //
390 // Search for L'\0' or L'/'.
391 //
392 }
393
394 if (Context->CurrentNode->Type != FSHELP_DIR) {
395 DEBUG ((DEBUG_INFO, "NTFS: Not a directory\n"));
396 return EFI_INVALID_PARAMETER;
397 }
398
399 if ((Next - Name == 1U) && (Name[0] == L'.')) {
400 continue;
401 }
402
403 if ((Next - Name == 2U) && (Name[0] == L'.') && (Name[1] == L'.')) {
404 GoUpALevel (Context);
405 continue;
406 }
407
408 PathPart = AllocateZeroPool ((Next - Name + 1U) * sizeof (CHAR16));
409 if (PathPart == NULL) {
410 return EFI_OUT_OF_RESOURCES;
411 }
412
413 CopyMem (PathPart, Name, (Next - Name) * sizeof (CHAR16));
414
415 IterCtx.Name = PathPart;
416 IterCtx.FoundNode = &FoundNode;
417 IterCtx.FoundType = &FoundType;
418
419 Status = IterateDir (Context->CurrentNode->Node, &IterCtx, FILE_ITER);
420 FreePool (PathPart);
421 if (EFI_ERROR (Status)) {
422 return Status;
423 }
424
425 if (FoundNode == NULL) {
426 break;
427 }
428
429 Status = PushNode (Context, FoundNode, FoundType);
430 if (EFI_ERROR (Status)) {
431 return Status;
432 }
433
434 if (Context->CurrentNode->Type == FSHELP_SYMLINK) {
435 if (++Context->SymlinkDepth == 8U) {
436 DEBUG ((DEBUG_INFO, "NTFS: Too deep nesting of symlinks\n"));
437 return EFI_INVALID_PARAMETER;
438 }
439
440 Symlink = ReadSymlink (Context->CurrentNode->Node);
441 if (Symlink == NULL) {
442 DEBUG ((DEBUG_INFO, "NTFS: Symlink leeds nowhere\n"));
443 return EFI_INVALID_PARAMETER;
444 }
445
446 if (Symlink[0] == L'/') {
447 //
448 // Symlink is an absolute path
449 //
450 Status = GoToRoot (Context);
451 if (EFI_ERROR (Status)) {
452 return Status;
453 }
454 } else {
455 GoUpALevel (Context);
456 }
457
458 Status = FindFile (Symlink, Context);
459 FreePool (Symlink);
460 if (EFI_ERROR (Status)) {
461 return Status;
462 }
463 }
464 }
465
466 DEBUG ((DEBUG_INFO, "NTFS: File `%s' not found\n", IterCtx.Name));
467 return EFI_NOT_FOUND;
468}
469
470EFI_STATUS
472 IN CONST CHAR16 *Path,
473 IN NTFS_FILE *RootNode,
474 OUT NTFS_FILE **FoundNode,
475 IN FSHELP_FILETYPE Type
476 )
477{
478 EFI_STATUS Status;
479 FSHELP_CTX Context;
480 FSHELP_FILETYPE FoundType;
481
482 ASSERT (Path != NULL);
483 ASSERT (RootNode != NULL);
484 ASSERT (FoundNode != NULL);
485
486 Context.Path = Path;
487 Context.RootNode = RootNode;
488 Context.SymlinkDepth = 0;
489 Context.CurrentNode = NULL;
490
491 if (Path[0] != L'/') {
492 DEBUG ((DEBUG_INFO, "NTFS: Invalid file name `%s'\n", Path));
493 return EFI_INVALID_PARAMETER;
494 }
495
496 Status = GoToRoot (&Context);
497 if (EFI_ERROR (Status)) {
498 return Status;
499 }
500
501 Status = FindFile ((CHAR16 *)Path, &Context);
502 if (EFI_ERROR (Status)) {
503 FreeStack (&Context);
504 return Status;
505 }
506
507 *FoundNode = Context.CurrentNode->Node;
508 FoundType = Context.CurrentNode->Type;
509 //
510 // Do not free the node
511 //
512 Context.CurrentNode->Node = NULL;
513 FreeStack (&Context);
514
515 if (FoundType != Type) {
516 if (*FoundNode != RootNode) {
517 FreeFile (*FoundNode);
518 FreePool (*FoundNode);
519 }
520
521 if (Type == FSHELP_REG) {
522 DEBUG ((DEBUG_INFO, "NTFS: Not a regular file\n"));
523 } else if (Type == FSHELP_DIR) {
524 DEBUG ((DEBUG_INFO, "NTFS: Not a directory\n"));
525 }
526
527 Status = EFI_VOLUME_CORRUPTED;
528 }
529
530 return Status;
531}
532
533EFI_STATUS
535 IN NTFS_FILE *Dir,
536 IN VOID *FileOrCtx,
537 IN FUNCTION_TYPE FunctionType
538 )
539{
540 EFI_STATUS Status;
541 NTFS_ATTR Attr;
542 ATTR_HEADER_RES *Res;
544 ATTR_INDEX_ROOT *Index;
545 INDEX_RECORD_HEADER *IndexRecord;
546 UINT8 *BitIndex;
547 UINT8 *BitMap;
548 UINTN BitMapLen;
549 UINT8 Bit;
550 UINTN Number;
551 UINTN FileRecordSize;
552 UINTN IndexRecordSize;
553
554 ASSERT (Dir != NULL);
555 ASSERT (FileOrCtx != NULL);
556
557 FileRecordSize = Dir->File->FileSystem->FileRecordSize;
558 IndexRecordSize = Dir->File->FileSystem->IndexRecordSize;
559
560 if (!Dir->InodeRead) {
561 Status = InitFile (Dir, Dir->Inode);
562 if (EFI_ERROR (Status)) {
563 return Status;
564 }
565 }
566
567 IndexRecord = NULL;
568 BitMap = NULL;
569
570 Status = InitAttr (&Attr, Dir);
571 if (EFI_ERROR (Status)) {
572 return Status;
573 }
574
575 //
576 // Search in $INDEX_ROOT
577 //
578 while (TRUE) {
579 Res = (ATTR_HEADER_RES *)FindAttr (&Attr, AT_INDEX_ROOT);
580 if (Res == NULL) {
581 DEBUG ((DEBUG_INFO, "NTFS: no $INDEX_ROOT\n"));
582 FreeAttr (&Attr);
583 return EFI_VOLUME_CORRUPTED;
584 }
585
586 mBufferSize = FileRecordSize - (Attr.Current - Attr.BaseMftRecord->FileRecord);
587
588 if ( (mBufferSize < sizeof (*Res))
589 || (mBufferSize < (Res->NameOffset + 8U))
590 || (mBufferSize < Res->InfoOffset))
591 {
592 DEBUG ((DEBUG_INFO, "NTFS: (IterateDir #1) $INDEX_ROOT is corrupted.\n"));
593 FreeAttr (&Attr);
594 return EFI_VOLUME_CORRUPTED;
595 }
596
597 mBufferSize -= Res->InfoOffset;
598
599 if ( (Res->NonResFlag != 0)
600 || (Res->NameLength != 4U)
601 || (Res->NameOffset != sizeof (*Res))
602 || (CompareMem ((UINT8 *)Res + Res->NameOffset, L"$I30", 8U) != 0))
603 {
604 continue;
605 }
606
607 if (mBufferSize < sizeof (*Index)) {
608 DEBUG ((DEBUG_INFO, "NTFS: (IterateDir #1.1) $INDEX_ROOT is corrupted.\n"));
609 FreeAttr (&Attr);
610 return EFI_VOLUME_CORRUPTED;
611 }
612
613 Index = (ATTR_INDEX_ROOT *)((UINT8 *)Res + Res->InfoOffset);
614 if (Index->Root.Type != AT_FILENAME) {
615 continue;
616 }
617
618 break;
619 }
620
621 if (mBufferSize < (sizeof (INDEX_ROOT) + Index->FirstEntryOffset)) {
622 DEBUG ((DEBUG_INFO, "NTFS: (IterateDir #2) $INDEX_ROOT is corrupted.\n"));
623 FreeAttr (&Attr);
624 return EFI_VOLUME_CORRUPTED;
625 }
626
627 mBufferSize -= sizeof (INDEX_ROOT) + Index->FirstEntryOffset;
628
629 Status = ListFile (
630 Dir,
631 (UINT8 *)Index + sizeof (INDEX_ROOT) + Index->FirstEntryOffset,
632 FileOrCtx,
633 FunctionType
634 );
635 if (!EFI_ERROR (Status)) {
636 FreeAttr (&Attr);
637 return EFI_SUCCESS;
638 }
639
640 //
641 // Search in $INDEX_ALLOCATION
642 //
643 BitIndex = NULL;
644 BitMapLen = 0;
645 FreeAttr (&Attr);
646
647 Status = InitAttr (&Attr, Dir);
648 if (EFI_ERROR (Status)) {
649 return Status;
650 }
651
652 while ((Non = (ATTR_HEADER_NONRES *)FindAttr (&Attr, AT_BITMAP)) != NULL) {
653 mBufferSize = FileRecordSize - (Attr.Current - Attr.BaseMftRecord->FileRecord);
654
655 if ( (mBufferSize < sizeof (*Non))
656 || (mBufferSize < (Non->NameOffset + 8U)))
657 {
658 DEBUG ((DEBUG_INFO, "NTFS: (IterateDir #3) $INDEX_ROOT is corrupted.\n"));
659 FreeAttr (&Attr);
660 return EFI_VOLUME_CORRUPTED;
661 }
662
663 if ( (Non->NameLength == 4U)
664 && (CompareMem ((UINT8 *)Non + Non->NameOffset, L"$I30", 8U) == 0))
665 {
666 BitMapLen = (Non->NonResFlag == 0) ?
667 ((ATTR_HEADER_RES *)Non)->InfoLength :
668 (UINTN)Non->AllocatedSize;
669
670 if (BitMapLen > MAX_FILE_SIZE) {
671 DEBUG ((DEBUG_INFO, "NTFS: (IterateDir) File is too huge.\n"));
672 return EFI_OUT_OF_RESOURCES;
673 }
674
675 BitMap = AllocateZeroPool (BitMapLen);
676 if (BitMap == NULL) {
677 FreeAttr (&Attr);
678 return EFI_OUT_OF_RESOURCES;
679 }
680
681 if (Non->NonResFlag == 0) {
682 if (mBufferSize < (((ATTR_HEADER_RES *)Non)->InfoOffset + BitMapLen)) {
683 DEBUG ((DEBUG_INFO, "NTFS: (IterateDir #4) $INDEX_ROOT is corrupted.\n"));
684 FreeAttr (&Attr);
685 FreePool (BitMap);
686 return EFI_VOLUME_CORRUPTED;
687 }
688
689 CopyMem (
690 BitMap,
691 (UINT8 *)Non + ((ATTR_HEADER_RES *)Non)->InfoOffset,
692 BitMapLen
693 );
694 } else {
695 Status = ReadData (&Attr, (UINT8 *)Non, BitMap, 0, BitMapLen);
696 if (EFI_ERROR (Status)) {
697 DEBUG ((DEBUG_INFO, "NTFS: Failed to read non-resident $BITMAP\n"));
698 FreeAttr (&Attr);
699 FreePool (BitMap);
700 return Status;
701 }
702
703 BitMapLen = (UINTN)Non->RealSize;
704 }
705
706 BitIndex = BitMap;
707 break;
708 }
709 }
710
711 FreeAttr (&Attr);
713
714 while (Non != NULL) {
715 mBufferSize = FileRecordSize - (Attr.Current - Attr.BaseMftRecord->FileRecord);
716
717 if ( (mBufferSize < sizeof (*Non))
718 || (mBufferSize < (Non->NameOffset + 8U)))
719 {
720 DEBUG ((DEBUG_INFO, "NTFS: (IterateDir #5) $INDEX_ROOT is corrupted.\n"));
721 FreeAttr (&Attr);
722 if (BitIndex != NULL) {
723 FreePool (BitMap);
724 }
725
726 return EFI_VOLUME_CORRUPTED;
727 }
728
729 if ( (Non->NonResFlag == 1U)
730 && (Non->NameLength == 4U)
731 && (Non->NameOffset == sizeof (*Non))
732 && (CompareMem ((UINT8 *)Non + Non->NameOffset, L"$I30", 8U) == 0))
733 {
734 break;
735 }
736
738 }
739
740 if ((Non == NULL) && (BitIndex != NULL)) {
741 DEBUG ((DEBUG_INFO, "NTFS: $BITMAP without $INDEX_ALLOCATION\n"));
742 FreeAttr (&Attr);
743 FreePool (BitMap);
744 return EFI_VOLUME_CORRUPTED;
745 }
746
747 if (BitIndex != NULL) {
748 IndexRecord = AllocateZeroPool (IndexRecordSize);
749 if (IndexRecord == NULL) {
750 FreeAttr (&Attr);
751 FreePool (BitMap);
752 return EFI_OUT_OF_RESOURCES;
753 }
754
755 Bit = 1U;
756 for (Number = 0; Number < (BitMapLen * 8U); Number++) {
757 if ((*BitIndex & Bit) != 0) {
758 Status = ReadAttr (
759 &Attr,
760 (UINT8 *)IndexRecord,
761 Number * IndexRecordSize,
762 IndexRecordSize
763 );
764 if (EFI_ERROR (Status)) {
765 FreeAttr (&Attr);
766 FreePool (BitMap);
767 FreePool (IndexRecord);
768 return Status;
769 }
770
771 Status = Fixup (
772 (UINT8 *)IndexRecord,
773 IndexRecordSize,
774 SIGNATURE_32 ('I', 'N', 'D', 'X'),
775 Dir->File->FileSystem->SectorSize
776 );
777 if (EFI_ERROR (Status)) {
778 FreeAttr (&Attr);
779 FreePool (BitMap);
780 FreePool (IndexRecord);
781 return Status;
782 }
783
784 if ( (IndexRecordSize < sizeof (*IndexRecord))
785 || (IndexRecordSize < (sizeof (INDEX_HEADER) + IndexRecord->IndexEntriesOffset)))
786 {
787 DEBUG ((DEBUG_INFO, "NTFS: $INDEX_ALLOCATION is corrupted.\n"));
788 FreeAttr (&Attr);
789 FreePool (BitMap);
790 FreePool (IndexRecord);
791 return EFI_VOLUME_CORRUPTED;
792 }
793
794 mBufferSize = IndexRecordSize - (sizeof (INDEX_HEADER) + IndexRecord->IndexEntriesOffset);
795
796 Status = ListFile (
797 Dir,
798 (UINT8 *)IndexRecord + sizeof (INDEX_HEADER) + IndexRecord->IndexEntriesOffset,
799 FileOrCtx,
800 FunctionType
801 );
802 if (!EFI_ERROR (Status)) {
803 FreeAttr (&Attr);
804 FreePool (BitMap);
805 FreePool (IndexRecord);
806 return Status;
807 }
808 }
809
810 Bit <<= 1U;
811 if (Bit == 0) {
812 Bit = 1U;
813 ++BitIndex;
814 }
815 }
816
817 FreeAttr (&Attr);
818 FreePool (BitMap);
819 FreePool (IndexRecord);
820 }
821
822 return Status;
823}
824
825EFI_STATUS
827 OUT CHAR16 *Dest,
828 IN CHAR16 *Source
829 )
830{
831 CHAR16 *Buffer;
832 CHAR16 *BPointer;
833 CHAR16 *Start;
834 CHAR16 *End;
835 UINT32 Skip;
836
837 ASSERT (Dest != NULL);
838 ASSERT (Source != NULL);
839
840 Skip = 0;
841
842 Buffer = AllocateZeroPool (StrSize (Source));
843 BPointer = Buffer;
844
845 End = Source + StrLen (Source);
846 Start = End;
847 while (Start > Source) {
848 while (*Start != L'/') {
849 --Start;
850 }
851
852 if ((Start[1] == L'.') && ((Start[2] == L'/') || (Start[2] == L'\0'))) {
853 End = Start;
854 --Start;
855 continue;
856 }
857
858 if ((Start[1] == L'.') && (Start[2] == L'.') && ((Start[3] == L'/') || (Start[3] == L'\0'))) {
859 End = Start;
860 --Start;
861 ++Skip;
862 continue;
863 }
864
865 if (Skip > 0) {
866 End = Start;
867 --Start;
868 --Skip;
869 continue;
870 }
871
872 CopyMem (
873 BPointer,
874 Start + 1U,
875 (End - Start - 1U) * sizeof (CHAR16)
876 );
877 BPointer += End - Start - 1U;
878
879 *BPointer = L'/';
880 ++BPointer;
881
882 End = Start;
883 --Start;
884 }
885
886 if (Skip > 0) {
887 DEBUG ((DEBUG_INFO, "NTFS: Invalid path: root has no parent.\n"));
888 FreePool (Buffer);
889 return EFI_DEVICE_ERROR;
890 }
891
892 End = BPointer - 1U;
893 Start = End - 1U;
894 while (Start > Buffer) {
895 while ((Start >= Buffer) && (*Start != L'/')) {
896 --Start;
897 }
898
899 *Dest = L'/';
900 ++Dest;
901
902 CopyMem (
903 Dest,
904 Start + 1U,
905 (End - Start - 1U) * sizeof (CHAR16)
906 );
907 Dest += End - Start - 1U;
908
909 End = Start;
910 --Start;
911 }
912
913 FreePool (Buffer);
914
915 return EFI_SUCCESS;
916}
917
927VOID
929 EFI_TIME *EfiTime,
930 UINT64 NtfsTime
931 )
932{
933 UINT64 Remainder64;
934 UINT32 Remainder32;
935 UINT16 Year;
936 UINT8 Month;
937 UINT32 Day;
938 UINT32 LastDay;
939 UINT32 PrevLD;
940 UINT8 Index;
941 UINT64 Temp;
942
943 ASSERT (EfiTime != NULL);
944
945 EfiTime->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
946 EfiTime->Pad1 = 0;
947 EfiTime->Daylight = 0;
948 EfiTime->Pad2 = 0;
949 //
950 // Because calendars are 1-based (there is no day 0), we have to add
951 // a day's worth of 100-ns units to make these calculations come out correct.
952 //
953 Year = GREGORIAN_START;
954 for (Temp = NtfsTime + DAY_IN_100NS; Temp > YEAR_IN_100NS; Temp -= YEAR_IN_100NS) {
955 if (LEAP_YEAR) {
956 //
957 // Subtract an extra day for leap year
958 //
959 Temp -= DAY_IN_100NS;
960 }
961
962 ++Year;
963 }
964
965 //
966 // From what's left, get the day, hour, minute, second and nanosecond.
967 //
968 Day = (UINT32)DivU64x64Remainder (Temp, DAY_IN_100NS, &Remainder64);
969 if (Day == 0) {
970 //
971 // Special handling for last day of year
972 //
973 Year -= 1U;
974 Day = LEAP_YEAR ? 366U : 365U;
975 }
976
977 EfiTime->Year = Year;
978 EfiTime->Hour = (UINT8)DivU64x64Remainder (Remainder64, HOUR_IN_100NS, &Remainder64);
979 EfiTime->Minute = (UINT8)DivU64x32Remainder (Remainder64, MINUTE_IN_100NS, &Remainder32);
980 EfiTime->Second = (UINT8)(Remainder32 / SECOND_IN_100NS);
981 Remainder32 %= SECOND_IN_100NS;
982 EfiTime->Nanosecond = Remainder32 * UNIT_IN_NS;
983 //
984 // "Day" now contains the ordinal date. We have to convert that to month and day.
985 //
986 Month = 1U;
987 LastDay = 31U;
988 PrevLD = 0;
989 for (Index = 1U; Index < 13U; ++Index) {
990 if (Day > LastDay) {
991 Month += 1U;
992 PrevLD = LastDay;
993 LastDay += mDaysPerMonth[Index];
994 if ((Index == 1U) && LEAP_YEAR) {
995 ++LastDay;
996 }
997 }
998 }
999
1000 EfiTime->Month = Month;
1001 EfiTime->Day = (UINT8)(Day - PrevLD);
1002}
UINT64 Start
EFI_DEVICE_PATH_PROTOCOL End
EFI_STATUS EFIAPI ReadAttr(IN NTFS_ATTR *Attr, OUT UINT8 *Dest, IN UINT64 Offset, IN UINTN Length)
Definition Data.c:184
EFI_STATUS EFIAPI ReadData(IN NTFS_ATTR *Attr, IN UINT8 *AttrStart, OUT UINT8 *Dest, IN UINT64 Offset, IN UINTN Length)
Definition Data.c:258
CHAR16 * ReadSymlink(IN NTFS_FILE *File)
Definition Data.c:565
UINT8 * LocateAttr(IN NTFS_ATTR *Attr, IN NTFS_FILE *Mft, IN UINT32 Type)
Definition Disc.c:347
VOID FreeFile(IN NTFS_FILE *File)
Definition Disc.c:810
VOID FreeAttr(IN NTFS_ATTR *Attr)
Definition Disc.c:792
EFI_STATUS InitAttr(OUT NTFS_ATTR *Attr, IN NTFS_FILE *File)
Definition Disc.c:313
UINT8 * FindAttr(IN NTFS_ATTR *Attr, IN UINT32 Type)
Definition Disc.c:400
EFI_STATUS EFIAPI Fixup(IN UINT8 *Buffer, IN UINT64 Length, IN UINT32 Magic, IN UINTN SectorSize)
Definition Disc.c:242
EFI_STATUS EFIAPI InitFile(IN OUT NTFS_FILE *File, IN UINT64 RecordNumber)
Definition Disc.c:727
@ POSIX
Definition Driver.h:204
@ DOS
Definition Driver.h:206
@ ATTR_REPARSE
Definition Driver.h:143
@ ATTR_DIRECTORY
Definition Driver.h:148
@ LAST_INDEX_ENTRY
Definition Driver.h:197
#define MAX_FILE_SIZE
Definition Driver.h:20
@ AT_INDEX_ROOT
Definition Driver.h:122
@ AT_INDEX_ALLOCATION
Definition Driver.h:123
@ AT_BITMAP
Definition Driver.h:124
@ AT_FILENAME
Definition Driver.h:116
#define MAX_PATH
Definition Driver.h:16
#define YEAR_IN_100NS
Definition Helper.h:20
FUNCTION_TYPE
Definition Helper.h:54
@ INFO_HOOK
Definition Helper.h:55
@ FILE_ITER
Definition Helper.h:57
@ DIR_HOOK
Definition Helper.h:56
#define SECOND_IN_100NS
Definition Helper.h:24
FSHELP_FILETYPE
Definition Helper.h:28
@ FSHELP_SYMLINK
Definition Helper.h:32
@ FSHELP_DIR
Definition Helper.h:31
@ FSHELP_REG
Definition Helper.h:30
@ FSHELP_UNKNOWN
Definition Helper.h:29
#define HOUR_IN_100NS
Definition Helper.h:22
#define LEAP_YEAR
Definition Helper.h:19
#define FSHELP_TYPE_MASK
Definition Helper.h:14
#define FSHELP_CASE_INSENSITIVE
Definition Helper.h:15
#define MINUTE_IN_100NS
Definition Helper.h:23
#define DAY_IN_100NS
Definition Helper.h:21
#define UNIT_IN_NS
Definition Helper.h:25
#define GREGORIAN_START
Definition Helper.h:26
STATIC EFI_STATUS GoToRoot(IN OUT FSHELP_CTX *Context)
Definition Index.c:105
VOID NtfsToEfiTime(EFI_TIME *EfiTime, UINT64 NtfsTime)
Definition Index.c:928
STATIC VOID FreeNode(IN OUT NTFS_FILE *Node OPTIONAL, IN FSHELP_CTX *Context)
Definition Index.c:18
EFI_STATUS RelativeToAbsolute(OUT CHAR16 *Dest, IN CHAR16 *Source)
Definition Index.c:826
STATIC EFI_STATUS ListFile(IN NTFS_FILE *Dir, IN UINT8 *Position, OUT VOID *FileOrCtx, IN FUNCTION_TYPE FunctionType)
Definition Index.c:234
STATIC UINT64 mBufferSize
Definition Index.c:12
STATIC VOID PopElement(IN OUT FSHELP_CTX *Context)
Definition Index.c:33
STATIC EFI_STATUS NtfsDirIter(IN CHAR16 *FileName, IN FSHELP_FILETYPE FileType, IN NTFS_FILE *Node, IN EFI_NTFS_FILE *File)
Definition Index.c:210
STATIC UINT8 mDaysPerMonth[]
Definition Index.c:13
STATIC EFI_STATUS NtfsDirHook(IN CHAR16 *Name, IN FSHELP_FILETYPE FileType, IN NTFS_FILE *Node, IN OUT EFI_FILE_INFO *Info)
Definition Index.c:154
STATIC EFI_STATUS PushNode(IN OUT FSHELP_CTX *Context, IN NTFS_FILE *Node, IN FSHELP_FILETYPE FileType)
Definition Index.c:79
EFI_STATUS IterateDir(IN NTFS_FILE *Dir, IN VOID *FileOrCtx, IN FUNCTION_TYPE FunctionType)
Definition Index.c:534
STATIC EFI_STATUS FindFile(IN CHAR16 *CurrentPath, IN FSHELP_CTX *Context)
Definition Index.c:359
INT64 mIndexCounter
Definition Index.c:14
EFI_STATUS FsHelpFindFile(IN CONST CHAR16 *Path, IN NTFS_FILE *RootNode, OUT NTFS_FILE **FoundNode, IN FSHELP_FILETYPE Type)
Definition Index.c:471
STATIC VOID GoUpALevel(IN OUT FSHELP_CTX *Context)
Definition Index.c:64
STATIC EFI_STATUS FindFileIter(IN CHAR16 *Name, IN FSHELP_FILETYPE FileType, IN NTFS_FILE *Node, IN FSHELP_ITER_CTX *Context)
Definition Index.c:117
STATIC VOID FreeStack(IN OUT FSHELP_CTX *Context)
Definition Index.c:51
INTN EFIAPI OcStriCmp(IN CONST CHAR16 *FirstString, IN CONST CHAR16 *SecondString)
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
UINT64 EFIAPI DivU64x32Remainder(IN UINT64 Dividend, IN UINT32 Divisor, OUT UINT32 *Remainder OPTIONAL)
Definition UserMath.c:25
UINT64 EFIAPI DivU64x64Remainder(IN UINT64 Dividend, IN UINT64 Divisor, OUT UINT64 *Remainder OPTIONAL)
Definition UserMath.c:59
#define ASSERT(x)
Definition coder.h:55
UINT8 * FileRecord
Definition Driver.h:615
UINT64 ReadTime
Definition Driver.h:619
UINT64 CreationTime
Definition Driver.h:617
UINT64 AlteredTime
Definition Driver.h:618
UINT64 Inode
Definition Driver.h:620
EFI_NTFS_FILE * File
Definition Driver.h:623
NTFS_FILE * Node
Definition Helper.h:37
FSHELP_FILETYPE Type
Definition Helper.h:38
struct _STACK_ELEMENT * Parent
Definition Helper.h:36
UINT64 CreationTime
Definition Driver.h:506
UINT8 Namespace
Definition Driver.h:515
UINT32 Flags
Definition Driver.h:512
UINT64 AlteredTime
Definition Driver.h:507
UINT8 FilenameLen
Definition Driver.h:514
UINT64 ReadTime
Definition Driver.h:509
UINT16 NameOffset
Definition Driver.h:327
UINT16 InfoOffset
Definition Driver.h:293
UINT8 NameLength
Definition Driver.h:288
UINT8 NonResFlag
Definition Driver.h:287
UINT16 NameOffset
Definition Driver.h:289
INDEX_ROOT Root
Definition Driver.h:476
UINT32 FirstEntryOffset
Definition Driver.h:477
CONST CHAR16 * Path
Definition Helper.h:42
NTFS_FILE * RootNode
Definition Helper.h:43
UINT32 SymlinkDepth
Definition Helper.h:44
STACK_ELEMENT * CurrentNode
Definition Helper.h:45
CONST CHAR16 * Name
Definition Helper.h:49
NTFS_FILE ** FoundNode
Definition Helper.h:50
FSHELP_FILETYPE * FoundType
Definition Helper.h:51
UINT8 Flags
Definition Driver.h:399
UINT16 IndexEntryLength
Definition Driver.h:397
UINT8 FileRecordNumber[6]
Definition Driver.h:395
UINT32 Type
Definition Driver.h:468
NTFS_FILE * BaseMftRecord
Definition Driver.h:611
UINT8 * Current
Definition Driver.h:608