[BOOTMGFW]
[reactos.git] / reactos / boot / environ / lib / io / etfs.c
1 /*
2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/io/etfs.c
5 * PURPOSE: Boot Library El Torito File System Management Routines
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12 #include "../drivers/filesystems/cdfs_new/cd.h"
13 typedef struct _RAW_ET_VD
14 {
15 UCHAR BootIndicator;
16 UCHAR StandardId[5];
17 UCHAR Version;
18 UCHAR SystemId[32];
19 UCHAR Reserved[32];
20 ULONG BootCatalogOffset;
21 UCHAR Padding[1973];
22 } RAW_ET_VD, *PRAW_ET_VD;
23
24 /* DATA VARIABLES ************************************************************/
25
26 typedef struct _BL_ETFS_DEVICE
27 {
28 ULONG RootDirOffset;
29 ULONG RootDirSize;
30 ULONG BlockSize;
31 ULONG VolumeSize;
32 BOOLEAN IsIso;
33 PUCHAR MemoryBlock;
34 ULONG Offset;
35 } BL_ETFS_DEVICE, *PBL_ETFS_DEVICE;
36
37 typedef struct _BL_ETFS_FILE
38 {
39 ULONG DirOffset;
40 ULONG DirEntOffset;
41 ULONGLONG Size;
42 ULONGLONG Offset;
43 PWCHAR FsName;
44 ULONG Flags;
45 ULONG DeviceId;
46 } BL_ETFS_FILE, *PBL_ETFS_FILE;
47
48 ULONG EtfsDeviceTableEntries;
49 PVOID* EtfsDeviceTable;
50
51 NTSTATUS
52 EtfsOpen (
53 _In_ PBL_FILE_ENTRY Directory,
54 _In_ PWCHAR FileName,
55 _In_ ULONG Flags,
56 _Out_ PBL_FILE_ENTRY *FileEntry
57 );
58
59 BL_FILE_CALLBACKS EtfsFunctionTable =
60 {
61 EtfsOpen,
62 };
63
64 /* FUNCTIONS *****************************************************************/
65
66 VOID
67 EtfspGetDirectoryInfo (
68 _In_ PBL_ETFS_DEVICE EtfsDevice,
69 _In_ PRAW_DIR_REC DirEntry,
70 _Out_ PULONG FileOffset,
71 _Out_ PULONG FileSize,
72 _Out_opt_ PBOOLEAN IsDirectory
73 )
74 {
75 ULONG SectorOffset;
76 BOOLEAN IsDir;
77
78 *FileOffset = *(PULONG)DirEntry->FileLoc * EtfsDevice->BlockSize;
79 *FileOffset += (DirEntry->XarLen * EtfsDevice->BlockSize);
80
81 SectorOffset = ALIGN_DOWN_BY(*FileOffset, CD_SECTOR_SIZE);
82
83 *FileSize = *(PULONG)DirEntry->DataLen;
84
85 IsDir = DE_FILE_FLAGS(EtfsDevice->IsIso, DirEntry) & ISO_ATTR_DIRECTORY;
86 if (IsDir)
87 {
88 *FileSize += ALIGN_UP_BY(SectorOffset, CD_SECTOR_SIZE) - SectorOffset;
89 }
90
91 if (IsDirectory)
92 {
93 *IsDirectory = IsDir;
94 }
95 }
96
97 USHORT
98 EtfspGetDirentNameLength (
99 _In_ PRAW_DIR_REC DirEntry
100 )
101 {
102 USHORT Length, RealLength;
103 PUCHAR Pos;
104
105 RealLength = Length = DirEntry->FileIdLen;
106 for (Pos = &DirEntry->FileIdLen + Length; Length; --Pos)
107 {
108 --Length;
109
110 if (*Pos == ';')
111 {
112 RealLength = Length;
113 break;
114 }
115 }
116
117 Length = RealLength;
118 for (Pos = &DirEntry->FileIdLen + Length; Length; --Pos)
119 {
120 --Length;
121
122 if (*Pos != '.')
123 {
124 break;
125 }
126
127 RealLength = Length;
128 }
129
130 return RealLength;
131 }
132
133 LONG
134 EtfspCompareNames (
135 __in PSTRING Name1,
136 __in PUNICODE_STRING Name2
137 )
138 {
139 ULONG i, l1, l2, l;
140
141 l1 = Name1->Length;
142 l2 = Name2->Length / sizeof(WCHAR);
143 l = min(l1, l2);
144
145 for (i = 0; i < l; i++)
146 {
147 if (toupper(Name1->Buffer[i]) != toupper(Name2->Buffer[i]))
148 {
149 return toupper(Name1->Buffer[i]) - toupper(Name2->Buffer[i]);
150 }
151 }
152
153 if (l2 <= l1)
154 {
155 return l2 < l1;
156 }
157 else
158 {
159 return -1;
160 }
161 }
162
163 BOOLEAN
164 EtfspFileMatch (
165 _In_ PRAW_DIR_REC DirEntry,
166 _In_ PUNICODE_STRING FileName
167 )
168 {
169 BOOLEAN Match;
170 USHORT Length;
171 ANSI_STRING DirName;
172
173 if ((DirEntry->FileIdLen != 1) ||
174 ((DirEntry->FileId[0] != 0) && (DirEntry->FileId[0] != 1)))
175 {
176 Length = EtfspGetDirentNameLength(DirEntry);
177 DirName.Length = Length;
178 DirName.MaximumLength = Length;
179 DirName.Buffer = (PCHAR)DirEntry->FileId;
180
181 Match = EtfspCompareNames(&DirName, FileName);
182 }
183 else
184 {
185 Match = -1;
186 }
187 return Match;
188 }
189
190 NTSTATUS
191 EtfspGetDirent (
192 _In_ PBL_FILE_ENTRY DirectoryEntry,
193 _Out_ PRAW_DIR_REC *DirEntry,
194 _Inout_ PULONG DirentOffset
195 )
196 {
197 PBL_ETFS_FILE EtfsFile;
198 ULONG FileOffset, DirectoryOffset, AlignedOffset, RemainderOffset;
199 ULONG DeviceId, ReadSize, DirLen;
200 PBL_ETFS_DEVICE EtfsDevice;
201 BOOLEAN NeedRead, IsMulti;
202 NTSTATUS result;
203 PRAW_DIR_REC DirEnt;
204 PUCHAR MemoryBlock;
205
206 EtfsFile = DirectoryEntry->FsSpecificData;
207 DeviceId = EtfsFile->DeviceId;
208 FileOffset = EtfsFile->Offset;
209 EtfsDevice = EtfsDeviceTable[DeviceId];
210
211 DirectoryOffset = *DirentOffset;
212 MemoryBlock = EtfsDevice->MemoryBlock;
213
214 IsMulti = 0;
215
216 AlignedOffset = (FileOffset + *DirentOffset) & ~CD_SECTOR_SIZE;
217 RemainderOffset = *DirentOffset + FileOffset - AlignedOffset;
218
219 ReadSize = 2048 - RemainderOffset;
220 NeedRead = AlignedOffset == EtfsDevice->Offset ? 0 : 1;
221
222 ReadAgain:
223 if (DirectoryOffset >= EtfsFile->Size)
224 {
225 return STATUS_NO_SUCH_FILE;
226 }
227
228 while (ReadSize < MIN_DIR_REC_SIZE)
229 {
230 DirectoryOffset += ReadSize;
231 AlignedOffset += 2048;
232 ReadSize = 2048;
233 RemainderOffset = 0;
234 NeedRead = 1;
235 if (DirectoryOffset >= EtfsFile->Size)
236 {
237 return STATUS_NO_SUCH_FILE;
238 }
239 }
240
241 if (NeedRead)
242 {
243 result = BlDeviceReadAtOffset(DirectoryEntry->DeviceId,
244 CD_SECTOR_SIZE,
245 AlignedOffset,
246 MemoryBlock,
247 NULL);
248 if (!NT_SUCCESS(result))
249 {
250 EfiPrintf(L"Device read failed %lx\r\n", result);
251 return result;
252 }
253
254 NeedRead = FALSE;
255 EtfsDevice->Offset = AlignedOffset;
256 }
257
258 if (!*(MemoryBlock + RemainderOffset))
259 {
260 AlignedOffset += 2048;
261 NeedRead = TRUE;
262
263 RemainderOffset = 0;
264 DirectoryOffset += ReadSize;
265 ReadSize = 2048;
266 goto ReadAgain;
267 }
268
269 DirEnt = (PRAW_DIR_REC)(MemoryBlock + RemainderOffset);
270 DirLen = DirEnt->DirLen;
271 if (DirLen > ReadSize)
272 {
273 EfiPrintf(L"Dir won't fit %lx %lx\r\n", DirLen, ReadSize);
274 return STATUS_NO_SUCH_FILE;
275 }
276
277 if (IsMulti)
278 {
279 if (!(DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI))
280 {
281 IsMulti = TRUE;
282 }
283 }
284 else if (DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI)
285 {
286 IsMulti = TRUE;
287 }
288 else
289 {
290 if ((DirEnt->FileIdLen != 1) ||
291 ((DirEnt->FileId[0] != 0) && (DirEnt->FileId[0] != 1)))
292 {
293 goto Quickie;
294 }
295 }
296
297 RemainderOffset += DirLen;
298 DirectoryOffset += DirLen;
299 ReadSize -= DirLen;
300 goto ReadAgain;
301
302 Quickie:
303 *DirEntry = DirEnt;
304 *DirentOffset = DirectoryOffset;
305 return STATUS_SUCCESS;
306 }
307
308 NTSTATUS
309 EtfspSearchForDirent (
310 _In_ PBL_FILE_ENTRY DirectoryEntry,
311 _In_ PWCHAR FileName,
312 _Out_ PRAW_DIR_REC *DirEntry,
313 _Out_ PULONG DirentOffset
314 )
315 {
316 UNICODE_STRING Name;
317 ULONG NextOffset;
318 PRAW_DIR_REC DirEnt;
319 NTSTATUS Status;
320
321 RtlInitUnicodeString(&Name, FileName);
322 for (NextOffset = *DirentOffset;
323 ;
324 NextOffset = NextOffset + DirEnt->DirLen)
325 {
326 Status = EtfspGetDirent(DirectoryEntry, &DirEnt, &NextOffset);
327 if (!NT_SUCCESS(Status))
328 {
329 return STATUS_NO_SUCH_FILE;
330 }
331
332 if (!EtfspFileMatch(DirEnt, &Name))
333 {
334 break;
335 }
336 }
337
338 *DirEntry = DirEnt;
339 *DirentOffset = NextOffset;
340 return 0;
341 }
342
343 NTSTATUS
344 EtfspCachedSearchForDirent (
345 _In_ PBL_FILE_ENTRY DirectoryEntry,
346 _In_ PWCHAR FileName,
347 _Out_ PRAW_DIR_REC *DirEntry,
348 _Out_ PULONG DirOffset,
349 _In_ BOOLEAN KeepOffset
350 )
351 {
352 PBL_ETFS_FILE EtfsFile;
353 PBL_ETFS_DEVICE EtfsDevice;
354 NTSTATUS Status;
355 ULONG DirentOffset;
356 PRAW_DIR_REC Dirent;
357 UNICODE_STRING Name;
358
359 EtfsFile = DirectoryEntry->FsSpecificData;
360 EtfsDevice = EtfsDeviceTable[EtfsFile->DeviceId];
361 RtlInitUnicodeString(&Name, FileName);
362 DirentOffset = EtfsFile->DirEntOffset;
363
364 if ((KeepOffset) ||
365 (ALIGN_DOWN_BY((DirentOffset + EtfsFile->Offset), CD_SECTOR_SIZE) ==
366 EtfsDevice->Offset))
367 {
368 Status = EtfspGetDirent(DirectoryEntry, &Dirent, &DirentOffset);
369 if (NT_SUCCESS(Status))
370 {
371 if (!EtfspFileMatch(Dirent, &Name))
372 {
373 *DirEntry = Dirent;
374 *DirOffset = DirentOffset;
375 return STATUS_SUCCESS;
376 }
377 }
378 else
379 {
380 DirentOffset = 0;
381 }
382 }
383 else
384 {
385 DirentOffset = 0;
386 }
387
388 Status = EtfspSearchForDirent(DirectoryEntry,
389 FileName,
390 DirEntry,
391 &DirentOffset);
392 if (!(NT_SUCCESS(Status)) && (DirentOffset))
393 {
394 DirentOffset = 0;
395 Status = EtfspSearchForDirent(DirectoryEntry,
396 FileName,
397 DirEntry,
398 &DirentOffset);
399 }
400
401 if (NT_SUCCESS(Status))
402 {
403 *DirOffset = DirentOffset;
404 }
405
406 return Status;
407 }
408
409 NTSTATUS
410 EtfsOpen (
411 _In_ PBL_FILE_ENTRY Directory,
412 _In_ PWCHAR FileName,
413 _In_ ULONG Flags,
414 _Out_ PBL_FILE_ENTRY *FileEntry
415 )
416 {
417 PBL_ETFS_DEVICE EtfsDevice;
418 NTSTATUS Status;
419 PBL_FILE_ENTRY NewFile;
420 PWCHAR FilePath, FormatString;
421 PBL_ETFS_FILE EtfsFile;
422 ULONG DeviceId, FileSize, DirOffset, FileOffset, Size;
423 PRAW_DIR_REC DirEntry;
424 BOOLEAN IsDirectory;
425
426 EfiPrintf(L"Attempting to open file %s in directory %s\r\n", FileName, Directory->FilePath);
427
428 EtfsFile = Directory->FsSpecificData;
429 DeviceId = EtfsFile->DeviceId;
430 EtfsDevice = EtfsDeviceTable[DeviceId];
431
432 /* Find the given file (or directory) in the given directory */
433 Status = EtfspCachedSearchForDirent(Directory,
434 FileName,
435 &DirEntry,
436 &DirOffset,
437 FALSE);
438 if (!NT_SUCCESS(Status))
439 {
440 EfiPrintf(L"no dirent found: %lx\r\n", Status);
441 return Status;
442 }
443
444 /* Find out information about the file (or directory) we found */
445 EtfspGetDirectoryInfo(EtfsDevice,
446 DirEntry,
447 &FileOffset,
448 &FileSize,
449 &IsDirectory);
450
451 NewFile = BlMmAllocateHeap(sizeof(*NewFile));
452 if (!NewFile)
453 {
454 return STATUS_NO_MEMORY;
455 }
456 RtlZeroMemory(NewFile, sizeof(*NewFile));
457
458 Size = wcslen(Directory->FilePath) + wcslen(FileName) + 2;
459
460 FilePath = BlMmAllocateHeap(Size * sizeof(WCHAR));
461 if (!FilePath)
462 {
463 Status = STATUS_NO_MEMORY;
464 goto Quickie;
465 }
466
467 EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile));
468 if (!EtfsFile)
469 {
470 Status = STATUS_NO_MEMORY;
471 goto Quickie;
472 }
473
474 RtlZeroMemory(NewFile, sizeof(*EtfsFile));
475
476 NewFile->DeviceId = Directory->DeviceId;
477 FormatString = L"%ls%ls";
478 if (Directory->FilePath[1])
479 {
480 FormatString = L"%ls\\%ls";
481 }
482
483 _snwprintf(FilePath, Size, FormatString, Directory->FilePath, FileName);
484 NewFile->FilePath = FilePath;
485
486 RtlCopyMemory(&NewFile->Callbacks,
487 &EtfsFunctionTable,
488 sizeof(NewFile->Callbacks));
489 EtfsFile->Offset = FileOffset;
490 EtfsFile->DirOffset = DirOffset;
491 EtfsFile->Size = FileSize;
492 EtfsFile->DeviceId = DeviceId;
493 if (IsDirectory)
494 {
495 EtfsFile->Flags |= 1;
496 NewFile->Flags |= 0x10000;
497 }
498 EtfsFile->FsName = L"cdfs";
499
500 NewFile->FsSpecificData = EtfsFile;
501 *FileEntry = NewFile;
502 return Status;
503
504 Quickie:
505
506 if (NewFile->FilePath)
507 {
508 BlMmFreeHeap(NewFile->FilePath);
509 }
510
511 if (NewFile->FsSpecificData)
512 {
513 BlMmFreeHeap(NewFile->FsSpecificData);
514 }
515
516 BlMmFreeHeap(NewFile);
517 return Status;
518 }
519
520 NTSTATUS
521 EtfspCheckCdfs (
522 _In_ PBL_ETFS_DEVICE EtfsDevice,
523 _In_ ULONG DeviceId,
524 _Out_ PRAW_ISO_VD *VolumeDescriptor,
525 _Out_ PBOOLEAN VolumeIsIso
526 )
527 {
528 EfiPrintf(L"Raw Cdfs not implemented\r\n");
529 return STATUS_NOT_IMPLEMENTED;
530 }
531
532 NTSTATUS
533 EtfspCheckEtfs (
534 _In_ PBL_ETFS_DEVICE EtfsDevice,
535 _In_ ULONG DeviceId,
536 _Out_ PRAW_ISO_VD *VolumeDescriptor,
537 _Out_ PBOOLEAN VolumeIsIso
538 )
539 {
540 PRAW_ISO_VD IsoVd;
541 PRAW_ET_VD EtVd;
542 NTSTATUS Status;
543 BOOLEAN IsIso;
544 BL_DEVICE_INFORMATION DeviceInformation;
545 ULONG Unknown, BytesRead;
546 ANSI_STRING CompareString, String;
547
548 /* Save our static buffer pointer */
549 IsoVd = (PRAW_ISO_VD)EtfsDevice->MemoryBlock;
550 EtVd = (PRAW_ET_VD)IsoVd;
551
552 /* First, read the El Torito Volume Descriptor */
553 BlDeviceGetInformation(DeviceId, &DeviceInformation);
554 Unknown = DeviceInformation.BlockDeviceInfo.Unknown;
555 DeviceInformation.BlockDeviceInfo.Unknown |= 1;
556 BlDeviceSetInformation(DeviceId, &DeviceInformation);
557 Status = BlDeviceReadAtOffset(DeviceId,
558 CD_SECTOR_SIZE,
559 (FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE,
560 EtfsDevice->MemoryBlock,
561 &BytesRead);
562 DeviceInformation.BlockDeviceInfo.Unknown = Unknown;
563 BlDeviceSetInformation(DeviceId, &DeviceInformation);
564 if (!NT_SUCCESS(Status))
565 {
566 EfiPrintf(L" read failed\r\n");
567 return Status;
568 }
569
570 /* Remember that's where we last read */
571 EtfsDevice->Offset = (FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE;
572
573 /* Check if it's EL TORITO! */
574 RtlInitString(&String, "EL TORITO SPECIFICATION");
575 CompareString.Buffer = (PCHAR)EtVd->SystemId;
576 CompareString.Length = 23;
577 CompareString.MaximumLength = 23;
578 if (!RtlEqualString(&CompareString, &String, TRUE))
579 {
580 return STATUS_UNSUCCESSFUL;
581 }
582
583 /* Check the version and boot indicator */
584 if ((EtVd->Version != 1) || (EtVd->BootIndicator))
585 {
586 return STATUS_UNSUCCESSFUL;
587 }
588
589 /* Check if it has the CD0001 identifier */
590 RtlInitString(&String, ISO_VOL_ID);
591 CompareString.Buffer = (PCHAR)EtVd->StandardId;
592 CompareString.Length = 5;
593 CompareString.MaximumLength = 5;
594 if (!RtlEqualString(&CompareString, &String, TRUE))
595 {
596 return STATUS_UNSUCCESSFUL;
597 }
598
599 /* Step two, we now want to read the ISO Volume Descriptor */
600 DeviceInformation.BlockDeviceInfo.Unknown |= 1u;
601 BlDeviceSetInformation(DeviceId, &DeviceInformation);
602 Status = BlDeviceReadAtOffset(DeviceId,
603 CD_SECTOR_SIZE,
604 FIRST_VD_SECTOR * CD_SECTOR_SIZE,
605 EtfsDevice->MemoryBlock,
606 &BytesRead);
607 DeviceInformation.BlockDeviceInfo.Unknown = Unknown;
608 BlDeviceSetInformation(DeviceId, &DeviceInformation);
609 if (!NT_SUCCESS(Status))
610 {
611 return Status;
612 }
613
614 /* Remember where we left off */
615 EtfsDevice->Offset = FIRST_VD_SECTOR * CD_SECTOR_SIZE;
616
617 /* This should also say CD0001 */
618 CompareString.Buffer = (PCHAR)IsoVd->StandardId;
619 CompareString.Length = 5;
620 CompareString.MaximumLength = 5;
621 IsIso = RtlEqualString(&CompareString, &String, TRUE);
622 if (!IsIso)
623 {
624 return STATUS_UNSUCCESSFUL;
625 }
626
627 /* And should be a version we support */
628 if ((IsoVd->Version != VERSION_1) || (IsoVd->DescType != VD_PRIMARY))
629 {
630 return STATUS_UNSUCCESSFUL;
631 }
632
633 /* Return back to the caller */
634 *VolumeDescriptor = IsoVd;
635 *VolumeIsIso = IsIso;
636 EfiPrintf(L"Recognized!!!\r\n");
637 return STATUS_SUCCESS;
638 }
639
640 NTSTATUS
641 EtfspDeviceContextDestroy (
642 _In_ PBL_ETFS_DEVICE EtfsDevice
643 )
644 {
645 if (EtfsDevice->MemoryBlock)
646 {
647 BlMmFreeHeap(EtfsDevice->MemoryBlock);
648 }
649
650 BlMmFreeHeap(EtfsDevice);
651
652 return STATUS_SUCCESS;
653 }
654
655 NTSTATUS
656 EtfspCreateContext (
657 _In_ ULONG DeviceId,
658 _Out_ PBL_ETFS_DEVICE *EtfsDevice
659 )
660 {
661 PBL_ETFS_DEVICE NewContext;
662 PVOID MemoryBlock;
663 NTSTATUS Status;
664 BOOLEAN IsIso;
665 PRAW_ISO_VD RawVd;
666
667 NewContext = (PBL_ETFS_DEVICE)BlMmAllocateHeap(sizeof(*NewContext));
668 if (!NewContext)
669 {
670 return STATUS_NO_MEMORY;
671 }
672 RtlZeroMemory(NewContext, sizeof(*NewContext));
673
674 MemoryBlock = BlMmAllocateHeap(CD_SECTOR_SIZE);
675 NewContext->MemoryBlock = MemoryBlock;
676 if (!MemoryBlock)
677 {
678 Status = STATUS_NO_MEMORY;
679 goto Quickie;
680 }
681
682 Status = EtfspCheckEtfs(NewContext, DeviceId, &RawVd, &IsIso);
683 if (!NT_SUCCESS(Status))
684 {
685 EfiPrintf(L"Drive not EDFS. Checking for CDFS: %lx\r\n");
686 Status = EtfspCheckCdfs(NewContext, DeviceId, &RawVd, &IsIso);
687 }
688
689 if (!NT_SUCCESS(Status))
690 {
691 EfiPrintf(L"Drive not CDFS. Failing: %lx\r\n");
692 goto Quickie;
693 }
694
695 NewContext->IsIso = IsIso;
696 NewContext->BlockSize = RVD_LB_SIZE(RawVd, IsIso);
697 NewContext->VolumeSize = RVD_VOL_SIZE(RawVd, IsIso);
698
699 EtfspGetDirectoryInfo(NewContext,
700 (PRAW_DIR_REC)RVD_ROOT_DE(RawVd, IsIso),
701 &NewContext->RootDirOffset,
702 &NewContext->RootDirSize,
703 0);
704 Status = STATUS_SUCCESS;
705
706 Quickie:
707 if (!NT_SUCCESS(Status))
708 {
709 EtfspDeviceContextDestroy(NewContext);
710 NewContext = NULL;
711 }
712
713 *EtfsDevice = NewContext;
714 return Status;
715 }
716
717 NTSTATUS
718 EtfspDeviceTableDestroyEntry (
719 _In_ PBL_ETFS_DEVICE EtfsDevice,
720 _In_ ULONG Index
721 )
722 {
723 EtfspDeviceContextDestroy(EtfsDevice);
724 EtfsDeviceTable[Index] = NULL;
725
726 return STATUS_SUCCESS;
727 }
728
729 NTSTATUS
730 EtfsMount (
731 _In_ ULONG DeviceId,
732 _In_ ULONG Unknown,
733 _Out_ PBL_FILE_ENTRY* FileEntry
734 )
735 {
736 PBL_ETFS_DEVICE EtfsDevice = NULL;
737 PBL_FILE_ENTRY RootEntry;
738 NTSTATUS Status;
739 PBL_ETFS_FILE EtfsFile;
740
741 EfiPrintf(L"Trying to mount as ETFS...\r\n");
742
743 Status = EtfspCreateContext(DeviceId, &EtfsDevice);
744 if (!NT_SUCCESS(Status))
745 {
746 EfiPrintf(L"ETFS context failed: %lx\r\n");
747 return Status;
748 }
749
750 Status = BlTblSetEntry(&EtfsDeviceTable,
751 &EtfsDeviceTableEntries,
752 EtfsDevice,
753 &DeviceId,
754 TblDoNotPurgeEntry);
755 if (!NT_SUCCESS(Status))
756 {
757 EtfspDeviceContextDestroy(EtfsDevice);
758 return Status;
759 }
760
761 RootEntry = BlMmAllocateHeap(sizeof(*RootEntry));
762 if (!RootEntry)
763 {
764 Status = STATUS_NO_MEMORY;
765 goto Quickie;
766 }
767
768 RtlZeroMemory(RootEntry, sizeof(*RootEntry));
769
770 RootEntry->FilePath = BlMmAllocateHeap(4);
771 if (!RootEntry->FilePath)
772 {
773 Status = STATUS_NO_MEMORY;
774 goto Quickie;
775 }
776
777 wcsncpy(RootEntry->FilePath, L"\\", 1);
778
779 RootEntry->DeviceId = DeviceId;
780 RtlCopyMemory(&RootEntry->Callbacks,
781 &EtfsFunctionTable,
782 sizeof(RootEntry->Callbacks));
783
784 EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile));
785 if (!EtfsFile)
786 {
787 Status = STATUS_NO_MEMORY;
788 goto Quickie;
789 }
790
791 RootEntry->Flags |= 0x10000;
792
793 RtlZeroMemory(EtfsFile, sizeof(*EtfsFile));
794 RootEntry->FsSpecificData = EtfsFile;
795 EtfsFile->DeviceId = DeviceId;
796 EtfsFile->Flags |= 1;
797 EtfsFile->Offset = EtfsDevice->RootDirOffset;
798 EtfsFile->DirOffset = 0;
799 EtfsFile->Size = EtfsDevice->RootDirSize;
800 EfiPrintf(L"Root offset: %I64x Size: %I64x\r\n", EtfsFile->Offset, EtfsFile->Size);
801 EtfsFile->FsName = L"cdfs";
802 *FileEntry = RootEntry;
803
804 return STATUS_SUCCESS;
805
806 Quickie:
807 if (RootEntry->FilePath)
808 {
809 BlMmFreeHeap(RootEntry->FilePath);
810 }
811 if (RootEntry->FsSpecificData)
812 {
813 BlMmFreeHeap(RootEntry->FsSpecificData);
814 }
815 if (RootEntry)
816 {
817 BlMmFreeHeap(RootEntry);
818 }
819
820 EtfspDeviceTableDestroyEntry(EtfsDevice, DeviceId);
821
822 return Status;
823 }
824
825 NTSTATUS
826 EtfsInitialize (
827 VOID
828 )
829 {
830 NTSTATUS Status;
831
832 /* Allocate the device table with 2 entries*/
833 EtfsDeviceTableEntries = 2;
834 EtfsDeviceTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) *
835 EtfsDeviceTableEntries);
836 if (EtfsDeviceTable)
837 {
838 /* Zero it out */
839 RtlZeroMemory(EtfsDeviceTable,
840 sizeof(PBL_FILE_ENTRY) * EtfsDeviceTableEntries);
841 Status = STATUS_SUCCESS;
842 }
843 else
844 {
845 /* No memory, fail */
846 Status = STATUS_NO_MEMORY;
847 }
848
849 /* Return back to caller */
850 return Status;
851 }
852