[BOOTLIB] Fix 64 bit issues (#433)
[reactos.git] / 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 <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 DiskOffset;
40 ULONG DirOffset;
41 ULONG DirEntOffset;
42
43 BL_FILE_INFORMATION;
44
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 NTSTATUS
60 EtfsGetInformation (
61 _In_ PBL_FILE_ENTRY FileEntry,
62 _Out_ PBL_FILE_INFORMATION FileInfo
63 );
64
65 NTSTATUS
66 EtfsSetInformation (
67 _In_ PBL_FILE_ENTRY FileEntry,
68 _In_ PBL_FILE_INFORMATION FileInfo
69 );
70
71 NTSTATUS
72 EtfsRead (
73 _In_ PBL_FILE_ENTRY FileEntry,
74 _In_ PVOID Buffer,
75 _In_ ULONG Size,
76 _Out_opt_ PULONG BytesReturned
77 );
78
79 BL_FILE_CALLBACKS EtfsFunctionTable =
80 {
81 EtfsOpen,
82 NULL,
83 EtfsRead,
84 NULL,
85 NULL,
86 EtfsGetInformation,
87 EtfsSetInformation
88 };
89
90 /* FUNCTIONS *****************************************************************/
91
92 VOID
93 EtfspGetDirectoryInfo (
94 _In_ PBL_ETFS_DEVICE EtfsDevice,
95 _In_ PRAW_DIR_REC DirEntry,
96 _Out_ PULONG FileOffset,
97 _Out_ PULONG FileSize,
98 _Out_opt_ PBOOLEAN IsDirectory
99 )
100 {
101 ULONG SectorOffset;
102 BOOLEAN IsDir;
103
104 *FileOffset = *(PULONG)DirEntry->FileLoc * EtfsDevice->BlockSize;
105 *FileOffset += (DirEntry->XarLen * EtfsDevice->BlockSize);
106
107 SectorOffset = ALIGN_DOWN_BY(*FileOffset, CD_SECTOR_SIZE);
108
109 *FileSize = *(PULONG)DirEntry->DataLen;
110
111 IsDir = DE_FILE_FLAGS(EtfsDevice->IsIso, DirEntry) & ISO_ATTR_DIRECTORY;
112 if (IsDir)
113 {
114 *FileSize += ALIGN_UP_BY(SectorOffset, CD_SECTOR_SIZE) - SectorOffset;
115 }
116
117 if (IsDirectory)
118 {
119 *IsDirectory = IsDir;
120 }
121 }
122
123 USHORT
124 EtfspGetDirentNameLength (
125 _In_ PRAW_DIR_REC DirEntry
126 )
127 {
128 USHORT Length, RealLength;
129 PUCHAR Pos;
130
131 RealLength = Length = DirEntry->FileIdLen;
132 for (Pos = DirEntry->FileId + Length - 1; Length; --Pos)
133 {
134 --Length;
135
136 if (*Pos == ';')
137 {
138 RealLength = Length;
139 break;
140 }
141 }
142
143 Length = RealLength;
144 for (Pos = DirEntry->FileId + Length - 1; Length; --Pos)
145 {
146 --Length;
147
148 if (*Pos != '.')
149 {
150 break;
151 }
152
153 RealLength = Length;
154 }
155
156 return RealLength;
157 }
158
159 LONG
160 EtfspCompareNames (
161 __in PSTRING Name1,
162 __in PUNICODE_STRING Name2
163 )
164 {
165 ULONG i, l1, l2, l;
166
167 l1 = Name1->Length;
168 l2 = Name2->Length / sizeof(WCHAR);
169 l = min(l1, l2);
170
171 for (i = 0; i < l; i++)
172 {
173 if (toupper(Name1->Buffer[i]) != toupper(Name2->Buffer[i]))
174 {
175 return toupper(Name1->Buffer[i]) - toupper(Name2->Buffer[i]);
176 }
177 }
178
179 if (l2 <= l1)
180 {
181 return l2 < l1;
182 }
183 else
184 {
185 return -1;
186 }
187 }
188
189 BOOLEAN
190 EtfspFileMatch (
191 _In_ PRAW_DIR_REC DirEntry,
192 _In_ PUNICODE_STRING FileName
193 )
194 {
195 BOOLEAN Match;
196 USHORT Length;
197 ANSI_STRING DirName;
198
199 if ((DirEntry->FileIdLen != 1) ||
200 ((DirEntry->FileId[0] != 0) && (DirEntry->FileId[0] != 1)))
201 {
202 Length = EtfspGetDirentNameLength(DirEntry);
203 DirName.Length = Length;
204 DirName.MaximumLength = Length;
205 DirName.Buffer = (PCHAR)DirEntry->FileId;
206
207 Match = EtfspCompareNames(&DirName, FileName);
208 }
209 else
210 {
211 Match = -1;
212 }
213 return Match;
214 }
215
216 NTSTATUS
217 EtfspGetDirent (
218 _In_ PBL_FILE_ENTRY DirectoryEntry,
219 _Out_ PRAW_DIR_REC *DirEntry,
220 _Inout_ PULONG DirentOffset
221 )
222 {
223 PBL_ETFS_FILE EtfsFile;
224 ULONG FileOffset, DirectoryOffset, AlignedOffset, RemainderOffset;
225 ULONG DeviceId, ReadSize, DirLen;
226 PBL_ETFS_DEVICE EtfsDevice;
227 BOOLEAN NeedRead, IsMulti;
228 NTSTATUS result;
229 PRAW_DIR_REC DirEnt;
230 PUCHAR MemoryBlock;
231
232 EtfsFile = DirectoryEntry->FsSpecificData;
233 DeviceId = EtfsFile->DeviceId;
234 FileOffset = EtfsFile->DiskOffset;
235 EtfsDevice = EtfsDeviceTable[DeviceId];
236
237 DirectoryOffset = *DirentOffset;
238 MemoryBlock = EtfsDevice->MemoryBlock;
239
240 IsMulti = 0;
241
242 AlignedOffset = (FileOffset + *DirentOffset) & ~CD_SECTOR_SIZE;
243 RemainderOffset = *DirentOffset + FileOffset - AlignedOffset;
244
245 ReadSize = 2048 - RemainderOffset;
246 NeedRead = AlignedOffset == EtfsDevice->Offset ? 0 : 1;
247
248 ReadAgain:
249 if (DirectoryOffset >= EtfsFile->Size)
250 {
251 return STATUS_NO_SUCH_FILE;
252 }
253
254 while (ReadSize < MIN_DIR_REC_SIZE)
255 {
256 DirectoryOffset += ReadSize;
257 AlignedOffset += 2048;
258 ReadSize = 2048;
259 RemainderOffset = 0;
260 NeedRead = 1;
261 if (DirectoryOffset >= EtfsFile->Size)
262 {
263 return STATUS_NO_SUCH_FILE;
264 }
265 }
266
267 if (NeedRead)
268 {
269 result = BlDeviceReadAtOffset(DirectoryEntry->DeviceId,
270 CD_SECTOR_SIZE,
271 AlignedOffset,
272 MemoryBlock,
273 NULL);
274 if (!NT_SUCCESS(result))
275 {
276 EfiPrintf(L"Device read failed %lx\r\n", result);
277 return result;
278 }
279
280 NeedRead = FALSE;
281 EtfsDevice->Offset = AlignedOffset;
282 }
283
284 if (!*(MemoryBlock + RemainderOffset))
285 {
286 AlignedOffset += 2048;
287 NeedRead = TRUE;
288
289 RemainderOffset = 0;
290 DirectoryOffset += ReadSize;
291 ReadSize = 2048;
292 goto ReadAgain;
293 }
294
295 DirEnt = (PRAW_DIR_REC)(MemoryBlock + RemainderOffset);
296 DirLen = DirEnt->DirLen;
297 if (DirLen > ReadSize)
298 {
299 EfiPrintf(L"Dir won't fit %lx %lx\r\n", DirLen, ReadSize);
300 return STATUS_NO_SUCH_FILE;
301 }
302
303 if (IsMulti)
304 {
305 if (!(DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI))
306 {
307 IsMulti = TRUE;
308 }
309 }
310 else if (DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI)
311 {
312 IsMulti = TRUE;
313 }
314 else
315 {
316 if ((DirEnt->FileIdLen != 1) ||
317 ((DirEnt->FileId[0] != 0) && (DirEnt->FileId[0] != 1)))
318 {
319 goto Quickie;
320 }
321 }
322
323 RemainderOffset += DirLen;
324 DirectoryOffset += DirLen;
325 ReadSize -= DirLen;
326 goto ReadAgain;
327
328 Quickie:
329 *DirEntry = DirEnt;
330 *DirentOffset = DirectoryOffset;
331 return STATUS_SUCCESS;
332 }
333
334 NTSTATUS
335 EtfspSearchForDirent (
336 _In_ PBL_FILE_ENTRY DirectoryEntry,
337 _In_ PWCHAR FileName,
338 _Out_ PRAW_DIR_REC *DirEntry,
339 _Out_ PULONG DirentOffset
340 )
341 {
342 UNICODE_STRING Name;
343 ULONG NextOffset;
344 PRAW_DIR_REC DirEnt;
345 NTSTATUS Status;
346
347 RtlInitUnicodeString(&Name, FileName);
348 for (NextOffset = *DirentOffset;
349 ;
350 NextOffset = NextOffset + DirEnt->DirLen)
351 {
352 Status = EtfspGetDirent(DirectoryEntry, &DirEnt, &NextOffset);
353 if (!NT_SUCCESS(Status))
354 {
355 return STATUS_NO_SUCH_FILE;
356 }
357
358 if (!EtfspFileMatch(DirEnt, &Name))
359 {
360 break;
361 }
362 }
363
364 *DirEntry = DirEnt;
365 *DirentOffset = NextOffset;
366 return 0;
367 }
368
369 NTSTATUS
370 EtfspCachedSearchForDirent (
371 _In_ PBL_FILE_ENTRY DirectoryEntry,
372 _In_ PWCHAR FileName,
373 _Out_ PRAW_DIR_REC *DirEntry,
374 _Out_ PULONG DirOffset,
375 _In_ BOOLEAN KeepOffset
376 )
377 {
378 PBL_ETFS_FILE EtfsFile;
379 PBL_ETFS_DEVICE EtfsDevice;
380 NTSTATUS Status;
381 ULONG DirentOffset;
382 PRAW_DIR_REC Dirent;
383 UNICODE_STRING Name;
384
385 EtfsFile = DirectoryEntry->FsSpecificData;
386 EtfsDevice = EtfsDeviceTable[EtfsFile->DeviceId];
387 RtlInitUnicodeString(&Name, FileName);
388 DirentOffset = EtfsFile->DirEntOffset;
389
390 if ((KeepOffset) ||
391 (ALIGN_DOWN_BY((DirentOffset + EtfsFile->DiskOffset), CD_SECTOR_SIZE) ==
392 EtfsDevice->Offset))
393 {
394 Status = EtfspGetDirent(DirectoryEntry, &Dirent, &DirentOffset);
395 if (NT_SUCCESS(Status))
396 {
397 if (!EtfspFileMatch(Dirent, &Name))
398 {
399 *DirEntry = Dirent;
400 *DirOffset = DirentOffset;
401 return STATUS_SUCCESS;
402 }
403 }
404 else
405 {
406 DirentOffset = 0;
407 }
408 }
409 else
410 {
411 DirentOffset = 0;
412 }
413
414 Status = EtfspSearchForDirent(DirectoryEntry,
415 FileName,
416 DirEntry,
417 &DirentOffset);
418 if (!(NT_SUCCESS(Status)) && (DirentOffset))
419 {
420 DirentOffset = 0;
421 Status = EtfspSearchForDirent(DirectoryEntry,
422 FileName,
423 DirEntry,
424 &DirentOffset);
425 }
426
427 if (NT_SUCCESS(Status))
428 {
429 *DirOffset = DirentOffset;
430 }
431
432 return Status;
433 }
434
435 NTSTATUS
436 EtfsRead (
437 _In_ PBL_FILE_ENTRY FileEntry,
438 _In_ PVOID Buffer,
439 _In_ ULONG Size,
440 _Out_opt_ PULONG BytesReturned
441 )
442 {
443 ULONG BytesRead;
444 PBL_ETFS_FILE EtfsFile;
445 NTSTATUS Status;
446
447 /* Assume failure for now */
448 BytesRead = 0;
449
450 /* Make sure that the read is within the file's boundaries */
451 EtfsFile = FileEntry->FsSpecificData;
452 if ((Size + EtfsFile->Offset) > EtfsFile->Size)
453 {
454 /* Bail out otherwise */
455 Status = STATUS_INVALID_PARAMETER;
456 }
457 else
458 {
459 /* Read the offset that matches this file's offset, on the disk */
460 Status = BlDeviceReadAtOffset(FileEntry->DeviceId,
461 Size,
462 EtfsFile->Offset + EtfsFile->DiskOffset,
463 Buffer,
464 &BytesRead);
465 if (NT_SUCCESS(Status))
466 {
467 /* Update the file offset and return the size as having been read */
468 EtfsFile->Offset += Size;
469 BytesRead = Size;
470 }
471 }
472
473 /* Check if caller wanted to know how many bytes were read */
474 if (BytesReturned)
475 {
476 /* Return the value */
477 *BytesReturned = BytesRead;
478 }
479
480 /* All done */
481 return Status;
482 }
483
484 NTSTATUS
485 EtfsSetInformation (
486 _In_ PBL_FILE_ENTRY FileEntry,
487 _In_ PBL_FILE_INFORMATION FileInfo
488 )
489 {
490 PBL_ETFS_FILE EtfsFile;
491 BL_FILE_INFORMATION LocalFileInfo;
492
493 /* Get the underlying ETFS file data structure */
494 EtfsFile = (PBL_ETFS_FILE)FileEntry->FsSpecificData;
495
496 /* Make a copy of the incoming attributes, but ignore the new offset */
497 LocalFileInfo = *FileInfo;
498 LocalFileInfo.Offset = EtfsFile->Offset;
499
500 /* Check if these match exactly the current file */
501 if (!RtlEqualMemory(&LocalFileInfo, &EtfsFile->Size, sizeof(*FileInfo)))
502 {
503 /* Nope -- which means caller is trying to change an immutable */
504 EfiPrintf(L"Incorrect information change\r\n");
505 return STATUS_INVALID_PARAMETER;
506 }
507
508 /* Is the offset past the end of the file? */
509 if (FileInfo->Offset >= EtfsFile->Size)
510 {
511 /* Don't allow EOF */
512 EfiPrintf(L"Offset too large: %lx vs %lx\r\n", FileInfo->Offset, EtfsFile->Size);
513 return STATUS_INVALID_PARAMETER;
514 }
515
516 /* Update the offset */
517 EtfsFile->Offset = FileInfo->Offset;
518 return STATUS_SUCCESS;
519 }
520
521 NTSTATUS
522 EtfsGetInformation (
523 _In_ PBL_FILE_ENTRY FileEntry,
524 _Out_ PBL_FILE_INFORMATION FileInfo
525 )
526 {
527 PBL_ETFS_FILE EtfsFile;
528
529 /* Get the underlying ETFS file data structure */
530 EtfsFile = (PBL_ETFS_FILE)FileEntry->FsSpecificData;
531
532 /* Copy the cached information structure within it */
533 RtlCopyMemory(FileInfo, &EtfsFile->Size, sizeof(*FileInfo));
534 return STATUS_SUCCESS;
535 }
536
537 NTSTATUS
538 EtfsOpen (
539 _In_ PBL_FILE_ENTRY Directory,
540 _In_ PWCHAR FileName,
541 _In_ ULONG Flags,
542 _Out_ PBL_FILE_ENTRY *FileEntry
543 )
544 {
545 PBL_ETFS_DEVICE EtfsDevice;
546 NTSTATUS Status;
547 PBL_FILE_ENTRY NewFile;
548 PWCHAR FilePath, FormatString;
549 PBL_ETFS_FILE EtfsFile;
550 ULONG DeviceId, FileSize, DirOffset, FileOffset;
551 SIZE_T Size;
552 PRAW_DIR_REC DirEntry;
553 BOOLEAN IsDirectory;
554
555 EtfsFile = Directory->FsSpecificData;
556 DeviceId = EtfsFile->DeviceId;
557 EtfsDevice = EtfsDeviceTable[DeviceId];
558
559 /* Find the given file (or directory) in the given directory */
560 Status = EtfspCachedSearchForDirent(Directory,
561 FileName,
562 &DirEntry,
563 &DirOffset,
564 FALSE);
565 if (!NT_SUCCESS(Status))
566 {
567 return Status;
568 }
569
570 /* Find out information about the file (or directory) we found */
571 EtfspGetDirectoryInfo(EtfsDevice,
572 DirEntry,
573 &FileOffset,
574 &FileSize,
575 &IsDirectory);
576
577 /* Allocate a file entry */
578 NewFile = BlMmAllocateHeap(sizeof(*NewFile));
579 if (!NewFile)
580 {
581 return STATUS_NO_MEMORY;
582 }
583
584 /* Zero it out */
585 RtlZeroMemory(NewFile, sizeof(*NewFile));
586
587 /* Figure out the size of the path and filename plus a slash and NUL */
588 Size = wcslen(Directory->FilePath) + wcslen(FileName) + 2;
589 FilePath = BlMmAllocateHeap(Size * sizeof(WCHAR));
590 if (!FilePath)
591 {
592 Status = STATUS_NO_MEMORY;
593 goto Quickie;
594 }
595
596 /* Allocate an ETFS file entry */
597 EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile));
598 if (!EtfsFile)
599 {
600 Status = STATUS_NO_MEMORY;
601 goto Quickie;
602 }
603
604 /* Zero it out */
605 RtlZeroMemory(EtfsFile, sizeof(*EtfsFile));
606
607 /* Capture the device ID of the directory */
608 NewFile->DeviceId = Directory->DeviceId;
609
610 /* Check if this is the root or a filename\directory under */
611 FormatString = L"%ls%ls";
612 if (Directory->FilePath[1])
613 {
614 FormatString = L"%ls\\%ls";
615 }
616
617 /* Combine the paths, and save the final path in the file entry */
618 _snwprintf(FilePath, Size, FormatString, Directory->FilePath, FileName);
619 NewFile->FilePath = FilePath;
620
621 /* Copy the ETFS function callbacks into the file netry */
622 RtlCopyMemory(&NewFile->Callbacks,
623 &EtfsFunctionTable,
624 sizeof(NewFile->Callbacks));
625
626 /* Fill out the rest of the details */
627 EtfsFile->DiskOffset = FileOffset;
628 EtfsFile->DirOffset = DirOffset;
629 EtfsFile->Size = FileSize;
630 EtfsFile->DeviceId = DeviceId;
631
632 /* Check if this is a directory */
633 if (IsDirectory)
634 {
635 EtfsFile->Flags |= BL_ETFS_FILE_ENTRY_DIRECTORY;
636 NewFile->Flags |= BL_FILE_ENTRY_DIRECTORY;
637 }
638
639 /* Write down the name of the filesystem */
640 EtfsFile->FsName = L"cdfs";
641
642 /* All done, return the file entry, and save the ETFS side */
643 NewFile->FsSpecificData = EtfsFile;
644 *FileEntry = NewFile;
645 return Status;
646
647 Quickie:
648 /* Failure path -- free the file path if we had one */
649 if (NewFile->FilePath)
650 {
651 BlMmFreeHeap(NewFile->FilePath);
652 }
653
654 /* Free the ETFS file entry if we had one */
655 if (NewFile->FsSpecificData)
656 {
657 BlMmFreeHeap(NewFile->FsSpecificData);
658 }
659
660 /* Free the file entry itself, and return the error code */
661 BlMmFreeHeap(NewFile);
662 return Status;
663 }
664
665 NTSTATUS
666 EtfspCheckCdfs (
667 _In_ PBL_ETFS_DEVICE EtfsDevice,
668 _In_ ULONG DeviceId,
669 _Out_ PRAW_ISO_VD *VolumeDescriptor,
670 _Out_ PBOOLEAN VolumeIsIso
671 )
672 {
673 EfiPrintf(L"Raw Cdfs not implemented\r\n");
674 return STATUS_NOT_IMPLEMENTED;
675 }
676
677 NTSTATUS
678 EtfspCheckEtfs (
679 _In_ PBL_ETFS_DEVICE EtfsDevice,
680 _In_ ULONG DeviceId,
681 _Out_ PRAW_ISO_VD *VolumeDescriptor,
682 _Out_ PBOOLEAN VolumeIsIso
683 )
684 {
685 PRAW_ISO_VD IsoVd;
686 PRAW_ET_VD EtVd;
687 NTSTATUS Status;
688 BOOLEAN IsIso;
689 BL_DEVICE_INFORMATION DeviceInformation;
690 ULONG Unknown, BytesRead;
691 ANSI_STRING CompareString, String;
692
693 /* Save our static buffer pointer */
694 IsoVd = (PRAW_ISO_VD)EtfsDevice->MemoryBlock;
695 EtVd = (PRAW_ET_VD)IsoVd;
696
697 /* First, read the El Torito Volume Descriptor */
698 BlDeviceGetInformation(DeviceId, &DeviceInformation);
699 Unknown = DeviceInformation.BlockDeviceInfo.Unknown;
700 DeviceInformation.BlockDeviceInfo.Unknown |= 1;
701 BlDeviceSetInformation(DeviceId, &DeviceInformation);
702 Status = BlDeviceReadAtOffset(DeviceId,
703 CD_SECTOR_SIZE,
704 (FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE,
705 EtfsDevice->MemoryBlock,
706 &BytesRead);
707 DeviceInformation.BlockDeviceInfo.Unknown = Unknown;
708 BlDeviceSetInformation(DeviceId, &DeviceInformation);
709 if (!NT_SUCCESS(Status))
710 {
711 EfiPrintf(L" read failed\r\n");
712 return Status;
713 }
714
715 /* Remember that's where we last read */
716 EtfsDevice->Offset = (FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE;
717
718 /* Check if it's EL TORITO! */
719 RtlInitString(&String, "EL TORITO SPECIFICATION");
720 CompareString.Buffer = (PCHAR)EtVd->SystemId;
721 CompareString.Length = 23;
722 CompareString.MaximumLength = 23;
723 if (!RtlEqualString(&CompareString, &String, TRUE))
724 {
725 return STATUS_UNSUCCESSFUL;
726 }
727
728 /* Check the version and boot indicator */
729 if ((EtVd->Version != 1) || (EtVd->BootIndicator))
730 {
731 return STATUS_UNSUCCESSFUL;
732 }
733
734 /* Check if it has the CD0001 identifier */
735 RtlInitString(&String, ISO_VOL_ID);
736 CompareString.Buffer = (PCHAR)EtVd->StandardId;
737 CompareString.Length = 5;
738 CompareString.MaximumLength = 5;
739 if (!RtlEqualString(&CompareString, &String, TRUE))
740 {
741 return STATUS_UNSUCCESSFUL;
742 }
743
744 /* Step two, we now want to read the ISO Volume Descriptor */
745 DeviceInformation.BlockDeviceInfo.Unknown |= 1u;
746 BlDeviceSetInformation(DeviceId, &DeviceInformation);
747 Status = BlDeviceReadAtOffset(DeviceId,
748 CD_SECTOR_SIZE,
749 FIRST_VD_SECTOR * CD_SECTOR_SIZE,
750 EtfsDevice->MemoryBlock,
751 &BytesRead);
752 DeviceInformation.BlockDeviceInfo.Unknown = Unknown;
753 BlDeviceSetInformation(DeviceId, &DeviceInformation);
754 if (!NT_SUCCESS(Status))
755 {
756 return Status;
757 }
758
759 /* Remember where we left off */
760 EtfsDevice->Offset = FIRST_VD_SECTOR * CD_SECTOR_SIZE;
761
762 /* This should also say CD0001 */
763 CompareString.Buffer = (PCHAR)IsoVd->StandardId;
764 CompareString.Length = 5;
765 CompareString.MaximumLength = 5;
766 IsIso = RtlEqualString(&CompareString, &String, TRUE);
767 if (!IsIso)
768 {
769 return STATUS_UNSUCCESSFUL;
770 }
771
772 /* And should be a version we support */
773 if ((IsoVd->Version != VERSION_1) || (IsoVd->DescType != VD_PRIMARY))
774 {
775 return STATUS_UNSUCCESSFUL;
776 }
777
778 /* Return back to the caller */
779 *VolumeDescriptor = IsoVd;
780 *VolumeIsIso = IsIso;
781 return STATUS_SUCCESS;
782 }
783
784 NTSTATUS
785 EtfspDeviceContextDestroy (
786 _In_ PBL_ETFS_DEVICE EtfsDevice
787 )
788 {
789 if (EtfsDevice->MemoryBlock)
790 {
791 BlMmFreeHeap(EtfsDevice->MemoryBlock);
792 }
793
794 BlMmFreeHeap(EtfsDevice);
795
796 return STATUS_SUCCESS;
797 }
798
799 NTSTATUS
800 EtfspCreateContext (
801 _In_ ULONG DeviceId,
802 _Out_ PBL_ETFS_DEVICE *EtfsDevice
803 )
804 {
805 PBL_ETFS_DEVICE NewContext;
806 PVOID MemoryBlock;
807 NTSTATUS Status;
808 BOOLEAN IsIso;
809 PRAW_ISO_VD RawVd;
810
811 NewContext = (PBL_ETFS_DEVICE)BlMmAllocateHeap(sizeof(*NewContext));
812 if (!NewContext)
813 {
814 return STATUS_NO_MEMORY;
815 }
816 RtlZeroMemory(NewContext, sizeof(*NewContext));
817
818 MemoryBlock = BlMmAllocateHeap(CD_SECTOR_SIZE);
819 NewContext->MemoryBlock = MemoryBlock;
820 if (!MemoryBlock)
821 {
822 Status = STATUS_NO_MEMORY;
823 goto Quickie;
824 }
825
826 Status = EtfspCheckEtfs(NewContext, DeviceId, &RawVd, &IsIso);
827 if (!NT_SUCCESS(Status))
828 {
829 EfiPrintf(L"Drive not EDFS. Checking for CDFS: %lx\r\n");
830 Status = EtfspCheckCdfs(NewContext, DeviceId, &RawVd, &IsIso);
831 }
832
833 if (!NT_SUCCESS(Status))
834 {
835 EfiPrintf(L"Drive not CDFS. Failing: %lx\r\n");
836 goto Quickie;
837 }
838
839 NewContext->IsIso = IsIso;
840 NewContext->BlockSize = RVD_LB_SIZE(RawVd, IsIso);
841 NewContext->VolumeSize = RVD_VOL_SIZE(RawVd, IsIso);
842
843 EtfspGetDirectoryInfo(NewContext,
844 (PRAW_DIR_REC)RVD_ROOT_DE(RawVd, IsIso),
845 &NewContext->RootDirOffset,
846 &NewContext->RootDirSize,
847 0);
848 Status = STATUS_SUCCESS;
849
850 Quickie:
851 if (!NT_SUCCESS(Status))
852 {
853 EtfspDeviceContextDestroy(NewContext);
854 NewContext = NULL;
855 }
856
857 *EtfsDevice = NewContext;
858 return Status;
859 }
860
861 NTSTATUS
862 EtfspDeviceTableDestroyEntry (
863 _In_ PBL_ETFS_DEVICE EtfsDevice,
864 _In_ ULONG Index
865 )
866 {
867 EtfspDeviceContextDestroy(EtfsDevice);
868 EtfsDeviceTable[Index] = NULL;
869
870 return STATUS_SUCCESS;
871 }
872
873 NTSTATUS
874 EtfsMount (
875 _In_ ULONG DeviceId,
876 _In_ ULONG Unknown,
877 _Out_ PBL_FILE_ENTRY* FileEntry
878 )
879 {
880 PBL_ETFS_DEVICE EtfsDevice = NULL;
881 PBL_FILE_ENTRY RootEntry;
882 NTSTATUS Status;
883 PBL_ETFS_FILE EtfsFile;
884
885 EfiPrintf(L"Trying to mount as ETFS...\r\n");
886
887 Status = EtfspCreateContext(DeviceId, &EtfsDevice);
888 if (!NT_SUCCESS(Status))
889 {
890 EfiPrintf(L"ETFS context failed: %lx\r\n");
891 return Status;
892 }
893
894 Status = BlTblSetEntry(&EtfsDeviceTable,
895 &EtfsDeviceTableEntries,
896 EtfsDevice,
897 &DeviceId,
898 TblDoNotPurgeEntry);
899 if (!NT_SUCCESS(Status))
900 {
901 EtfspDeviceContextDestroy(EtfsDevice);
902 return Status;
903 }
904
905 RootEntry = BlMmAllocateHeap(sizeof(*RootEntry));
906 if (!RootEntry)
907 {
908 Status = STATUS_NO_MEMORY;
909 goto Quickie;
910 }
911
912 RtlZeroMemory(RootEntry, sizeof(*RootEntry));
913
914 RootEntry->FilePath = BlMmAllocateHeap(4);
915 if (!RootEntry->FilePath)
916 {
917 Status = STATUS_NO_MEMORY;
918 goto Quickie;
919 }
920
921 wcsncpy(RootEntry->FilePath, L"\\", 1);
922
923 RootEntry->DeviceId = DeviceId;
924 RtlCopyMemory(&RootEntry->Callbacks,
925 &EtfsFunctionTable,
926 sizeof(RootEntry->Callbacks));
927
928 EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile));
929 if (!EtfsFile)
930 {
931 Status = STATUS_NO_MEMORY;
932 goto Quickie;
933 }
934
935 RootEntry->Flags |= 0x10000;
936
937 RtlZeroMemory(EtfsFile, sizeof(*EtfsFile));
938 RootEntry->FsSpecificData = EtfsFile;
939 EtfsFile->DeviceId = DeviceId;
940 EtfsFile->Flags |= 1;
941 EtfsFile->DiskOffset = EtfsDevice->RootDirOffset;
942 EtfsFile->DirOffset = 0;
943 EtfsFile->Size = EtfsDevice->RootDirSize;
944 EtfsFile->FsName = L"cdfs";
945 *FileEntry = RootEntry;
946
947 return STATUS_SUCCESS;
948
949 Quickie:
950 if (RootEntry->FilePath)
951 {
952 BlMmFreeHeap(RootEntry->FilePath);
953 }
954 if (RootEntry->FsSpecificData)
955 {
956 BlMmFreeHeap(RootEntry->FsSpecificData);
957 }
958 if (RootEntry)
959 {
960 BlMmFreeHeap(RootEntry);
961 }
962
963 EtfspDeviceTableDestroyEntry(EtfsDevice, DeviceId);
964
965 return Status;
966 }
967
968 NTSTATUS
969 EtfsInitialize (
970 VOID
971 )
972 {
973 NTSTATUS Status;
974
975 /* Allocate the device table with 2 entries*/
976 EtfsDeviceTableEntries = 2;
977 EtfsDeviceTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) *
978 EtfsDeviceTableEntries);
979 if (EtfsDeviceTable)
980 {
981 /* Zero it out */
982 RtlZeroMemory(EtfsDeviceTable,
983 sizeof(PBL_FILE_ENTRY) * EtfsDeviceTableEntries);
984 Status = STATUS_SUCCESS;
985 }
986 else
987 {
988 /* No memory, fail */
989 Status = STATUS_NO_MEMORY;
990 }
991
992 /* Return back to caller */
993 return Status;
994 }
995