2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/io/file.c
5 * PURPOSE: Boot Library File Management Routines
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
13 /* DATA VARIABLES ************************************************************/
18 LIST_ENTRY RegisteredFileSystems
;
19 BL_FILE_SYSTEM_REGISTRATION_TABLE FatRegisterFunctionTable
=
26 BL_FILE_SYSTEM_REGISTRATION_TABLE EtfsRegisterFunctionTable
=
34 extern ULONG DmTableEntries
;
35 extern PVOID
* DmDeviceTable
;
37 /* FUNCTIONS *****************************************************************/
40 FileIoCopyParentDirectoryPath (
44 SIZE_T PathSize
, PathSizeWithNull
;
45 PWCHAR Backslash
, ParentCopy
;
47 PathSize
= wcslen(FilePath
) * sizeof(WCHAR
);
49 PathSizeWithNull
= PathSize
+ sizeof(UNICODE_NULL
);
50 if (PathSizeWithNull
< PathSize
)
55 ParentCopy
= BlMmAllocateHeap(PathSizeWithNull
);
60 wcsncpy(ParentCopy
, FilePath
, PathSizeWithNull
/ sizeof(WCHAR
));
62 Backslash
= wcsrchr(ParentCopy
, '\\');
65 BlMmFreeHeap(ParentCopy
);
69 if (Backslash
== ParentCopy
)
74 *Backslash
= UNICODE_NULL
;
83 PWCHAR Separator
, FileCopy
;
86 Separator
= wcsrchr(FilePath
, '\\');
92 PathSize
= wcslen(Separator
) * sizeof(WCHAR
);
94 FileCopy
= BlMmAllocateHeap(PathSize
);
100 wcsncpy(FileCopy
, Separator
+ 1, PathSize
/ sizeof(WCHAR
));
105 FileTableCompareWithSubsetAttributes (
107 _In_ PVOID Argument1
,
108 _In_ PVOID Argument2
,
109 _In_ PVOID Argument3
,
113 PBL_FILE_ENTRY FileEntry
= (PBL_FILE_ENTRY
)Entry
;
114 ULONG DeviceId
= *(PULONG
)Argument1
;
115 PWCHAR FilePath
= (PWCHAR
)Argument2
;
116 ULONG Flags
= *(PULONG
)Argument3
;
117 ULONG Unknown
= *(PULONG
)Argument4
;
122 if ((FileEntry
->DeviceId
== DeviceId
) &&
123 !(_wcsicmp(FileEntry
->FilePath
, FilePath
)) &&
124 (FileEntry
->Unknown
== Unknown
))
126 if ((!(Flags
& 1) || (FileEntry
->Flags
& 2)) && (!(Flags
& 2) || (FileEntry
->Flags
& 4)))
128 if ((!(Flags
& 4) || (FileEntry
->Flags
& 0x10000)) && ((Flags
& 4) || !(FileEntry
->Flags
& 0x10000)))
138 FileTableCompareWithSameAttributes (
140 _In_ PVOID Argument1
,
141 _In_ PVOID Argument2
,
142 _In_ PVOID Argument3
,
146 PBL_FILE_ENTRY FileEntry
= (PBL_FILE_ENTRY
)Entry
;
147 ULONG DeviceId
= *(PULONG
)Argument1
;
148 PWCHAR FilePath
= (PWCHAR
)Argument2
;
149 ULONG Flags
= *(PULONG
)Argument3
;
150 ULONG Unknown
= *(PULONG
)Argument4
;
155 if ((FileEntry
->DeviceId
== DeviceId
) &&
156 !(_wcsicmp(FileEntry
->FilePath
, FilePath
)) &&
157 (FileEntry
->Unknown
== Unknown
))
159 if ((!(Flags
& 1) || (FileEntry
->Flags
& 2)) && ((Flags
& 1) || !(FileEntry
->Flags
& 2)) && (!(Flags
& 2) || (FileEntry
->Flags
& 4)) && ((Flags
& 2) || !(FileEntry
->Flags
& 4)))
161 if ((!(Flags
& 4) || (FileEntry
->Flags
& 0x10000)) && ((Flags
& 4) || !(FileEntry
->Flags
& 0x10000)))
171 FileTableDestroyEntry (
172 _In_ PBL_FILE_ENTRY FileEntry
,
177 PBL_DEVICE_ENTRY DeviceEntry
;
180 DeviceId
= FileEntry
->DeviceId
;
181 if (DmTableEntries
> DeviceId
)
183 DeviceEntry
= DmDeviceTable
[DeviceId
];
186 --DeviceEntry
->ReferenceCount
;
190 Status
= FileEntry
->Callbacks
.Close(FileEntry
);
192 BlMmFreeHeap(FileEntry
);
194 FileTable
[Index
] = NULL
;
198 #define BL_FILE_PURGE_LIMIT 512
201 FileTablePurgeEntry (
205 PBL_FILE_ENTRY FileEntry
= (PBL_FILE_ENTRY
)Entry
;
207 /* Don't purge opened files, or if there's less than 512 files cached */
208 if (((FileEntry
->Flags
& BL_FILE_ENTRY_OPENED
) ||
209 (FileEntry
->Flags
& 0x10000)) &&
210 (FileEntries
< BL_FILE_PURGE_LIMIT
))
212 return STATUS_UNSUCCESSFUL
;
215 /* Purge the entry otherwise */
216 return FileTableDestroyEntry(FileEntry
, FileEntry
->FileId
);
224 PBL_FILE_ENTRY FileEntry
;
226 /* Validate the file ID */
227 if (FileEntries
<= FileId
)
229 return STATUS_INVALID_PARAMETER
;
232 /* Make sure a file entry actually exists */
233 FileEntry
= FileTable
[FileId
];
236 return STATUS_INVALID_PARAMETER
;
239 /* And that it's actually open */
240 if (!(FileEntry
->Flags
& BL_FILE_ENTRY_OPENED
))
242 return STATUS_INVALID_PARAMETER
;
245 /* Drop a reference, check if this was the last one */
246 --FileEntry
->ReferenceCount
;
247 if (!FileEntry
->ReferenceCount
)
249 /* File is no longer open */
250 FileEntry
->Flags
&= ~BL_FILE_ENTRY_OPENED
;
254 return STATUS_SUCCESS
;
260 _In_ PWCHAR FileName
,
263 _In_ PBL_TBL_LOOKUP_ROUTINE CompareRoutine
,
264 _Out_opt_ PBL_FILE_ENTRY
*NewFileEntry
267 PWCHAR FileNameCopy
, ParentFileName
;
269 PBL_DEVICE_ENTRY DeviceEntry
;
270 PBL_FILE_SYSTEM_ENTRY FileSystem
;
271 ULONG FileId
, CheckFlags
;
272 PBL_FILE_ENTRY DirectoryEntry
, FileEntry
;
273 PLIST_ENTRY NextEntry
, ListHead
;
275 /* Preinitialize variables for failure */
276 DirectoryEntry
= NULL
;
278 ParentFileName
= NULL
;
279 Status
= STATUS_SUCCESS
;
281 /* Bail out if the device ID is invalid */
282 if (DmTableEntries
<= DeviceId
)
284 return STATUS_ACCESS_DENIED
;
287 /* Bail out if there's no device entry */
288 DeviceEntry
= DmDeviceTable
[DeviceId
];
291 return STATUS_ACCESS_DENIED
;
294 /* Read access is always required for touching the device */
295 CheckFlags
= Flags
| BL_FILE_READ_ACCESS
;
297 /* Check if the device is granting us read access */
298 if ((CheckFlags
& BL_FILE_READ_ACCESS
) &&
299 (!(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
) ||
300 !(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_READ_ACCESS
)))
302 EfiPrintf(L
"Access denied\r\n");
303 return STATUS_ACCESS_DENIED
;
306 /* Check if the device is granting us write access */
307 if ((CheckFlags
& BL_FILE_WRITE_ACCESS
) &&
308 (!(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
) ||
309 !(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_WRITE_ACCESS
)))
311 EfiPrintf(L
"Access denied2\r\n");
312 return STATUS_ACCESS_DENIED
;
315 /* Check if we already have this file open */
316 FileEntry
= (PBL_FILE_ENTRY
)BlTblFindEntry(FileTable
,
329 /* Check if we are opening the root drive or an actual file/directory */
330 if ((*FileName
!= OBJ_NAME_PATH_SEPARATOR
) || (FileName
[1]))
332 /* Get the name of the directory */
333 ParentFileName
= FileIoCopyParentDirectoryPath(FileName
);
336 Status
= STATUS_NO_MEMORY
;
341 Status
= FileIoOpen(DeviceId
,
343 BL_FILE_READ_ACCESS
| BL_DIRECTORY_ACCESS
,
345 FileTableCompareWithSubsetAttributes
,
347 if (!NT_SUCCESS(Status
))
352 /* Now get the the file name itself */
353 FileNameCopy
= FileIoCopyFileName(FileName
);
356 Status
= STATUS_NO_MEMORY
;
361 Status
= DirectoryEntry
->Callbacks
.Open(DirectoryEntry
,
368 /* We're opening the root, scan through all the file systems */
369 Status
= STATUS_UNSUCCESSFUL
;
370 ListHead
= &RegisteredFileSystems
;
371 NextEntry
= ListHead
->Flink
;
372 while (NextEntry
!= ListHead
)
374 /* Try to mount this one */
375 FileSystem
= CONTAINING_RECORD(NextEntry
, BL_FILE_SYSTEM_ENTRY
, ListEntry
);
376 Status
= FileSystem
->MountCallback(DeviceId
, Unknown
, &FileEntry
);
377 if (NT_SUCCESS(Status
))
379 /* Mount successful */
383 /* Try the next file system */
384 NextEntry
= NextEntry
->Flink
;
387 /* Nothing to free on this path */
392 if (!NT_SUCCESS(Status
))
394 EfiPrintf(L
"Could not open file!: %lx\r\n", Status
);
398 /* Save the unknown */
399 FileEntry
->Unknown
= Unknown
;
401 /* Convert open flags into entry flags */
402 if (Flags
& BL_FILE_READ_ACCESS
)
404 FileEntry
->Flags
|= BL_FILE_ENTRY_READ_ACCESS
;
406 if (Flags
& BL_FILE_WRITE_ACCESS
)
408 FileEntry
->Flags
|= BL_FILE_ENTRY_WRITE_ACCESS
;
411 /* Save the file into the file table */
412 Status
= BlTblSetEntry(&FileTable
,
416 FileTablePurgeEntry
);
417 if (!NT_SUCCESS(Status
))
419 /* Close it if that failed */
420 FileEntry
->Callbacks
.Close(FileEntry
);
424 /* Add a reference on the device, and save our file ID */
425 ++DeviceEntry
->ReferenceCount
;
426 Status
= STATUS_SUCCESS
;
427 FileEntry
->FileId
= FileId
;
430 /* Add a reference to the file entry, and see if this is the first one */
431 if (++FileEntry
->ReferenceCount
== 1)
434 FileEntry
->TotalBytesRead
= 0;
435 FileEntry
->Unknown2
= 0;
438 /* Set the file as opened */
439 FileEntry
->Flags
|= BL_FILE_ENTRY_OPENED
;
441 /* Not sure what this flag does */
442 if (Flags
& BL_UNKNOWN_ACCESS
)
444 FileEntry
->Flags
|= BL_FILE_ENTRY_UNKNOWN_ACCESS
;
447 /* If the caller wanted the entry back, return it */
450 *NewFileEntry
= FileEntry
;
454 /* Close the parent */
457 BlFileClose(DirectoryEntry
->FileId
);
460 /* Free the parent name copy */
463 BlMmFreeHeap(ParentFileName
);
466 /* Free the file name copy */
469 BlMmFreeHeap(FileNameCopy
);
472 /* Return back to caller */
479 _In_ PWCHAR FileName
,
485 PBL_FILE_ENTRY FileEntry
;
486 BL_DEVICE_INFORMATION DeviceInformation
;
488 /* Make sure we have a valid file name, access flags and parameters */
490 (*FileName
!= OBJ_NAME_PATH_SEPARATOR
) ||
492 !(Flags
& (BL_FILE_READ_ACCESS
| BL_FILE_WRITE_ACCESS
)))
494 EfiPrintf(L
"Invalid file options\r\n");
495 return STATUS_INVALID_PARAMETER
;
498 /* Get information on the underlying device */
499 Status
= BlDeviceGetInformation(DeviceId
, &DeviceInformation
);
500 if (!NT_SUCCESS(Status
))
502 EfiPrintf(L
"Get device info failed: %lx\r\n", Status
);
506 /* Make sure it's a device that can host files */
507 if ((DeviceInformation
.DeviceType
!= DiskDevice
) &&
508 (DeviceInformation
.DeviceType
!= LegacyPartitionDevice
) &&
509 (DeviceInformation
.DeviceType
!= UdpDevice
))
511 EfiPrintf(L
"Invalid device type\r\n");
512 return STATUS_INVALID_PARAMETER
;
515 /* Open a file on this device, creating one if needed */
516 Status
= FileIoOpen(DeviceId
,
520 FileTableCompareWithSameAttributes
,
522 if (NT_SUCCESS(Status
))
524 /* Return the file ID back to the caller */
525 *FileId
= FileEntry
->FileId
;
533 BlFileSetInformation (
535 _Out_ PBL_FILE_INFORMATION FileInfo
538 PBL_FILE_ENTRY FileEntry
;
540 /* Make sure caller passed this in */
543 return STATUS_INVALID_PARAMETER
;
546 /* Validate file ID */
547 if (FileId
> FileEntries
)
549 return STATUS_INVALID_PARAMETER
;
552 /* Make sure an opened file exits with this ID */
553 FileEntry
= FileTable
[FileId
];
554 if (!(FileEntry
) || !(FileEntry
->Flags
& BL_FILE_ENTRY_OPENED
))
556 return STATUS_INVALID_PARAMETER
;
559 /* Do the I/O operation */
560 return FileEntry
->Callbacks
.SetInfo(FileEntry
, FileInfo
);
564 BlFileGetInformation (
566 _In_ PBL_FILE_INFORMATION FileInfo
569 PBL_FILE_ENTRY FileEntry
;
571 /* Make sure caller passed this in */
574 return STATUS_INVALID_PARAMETER
;
577 /* Validate file ID */
578 if (FileId
> FileEntries
)
580 return STATUS_INVALID_PARAMETER
;
583 /* Make sure an opened file exits with this ID */
584 FileEntry
= FileTable
[FileId
];
585 if (!(FileEntry
) || !(FileEntry
->Flags
& BL_FILE_ENTRY_OPENED
))
587 return STATUS_INVALID_PARAMETER
;
590 /* Do the I/O operation */
591 return FileEntry
->Callbacks
.GetInfo(FileEntry
, FileInfo
);
595 FileInformationCheck (
596 _In_ PBL_FILE_INFORMATION FileInformation
,
598 _In_opt_ PULONG InputSize
,
599 _In_opt_ PULONG BytesReturned
,
600 _Out_opt_ PULONG RequiredSize
606 /* Initialize variables */
607 Status
= STATUS_SUCCESS
;
610 /* Make sure we didn't overshoot */
611 if (FileInformation
->Offset
> FileInformation
->Size
)
614 Status
= STATUS_INVALID_PARAMETER
;
618 /* Compute the appropriate 32-bit size of this read, based on file size */
620 if ((FileInformation
->Size
- FileInformation
->Offset
) <= ULONG_MAX
)
622 Size
= (ULONG
)(FileInformation
->Size
) - (ULONG
)(FileInformation
->Offset
);
625 /* Check if the caller has an input buffer */
628 /* Is the size bigger than what the caller can handle? */
629 if (Size
>= *InputSize
)
631 /* Yes, so cap it at the size of the caller's buffer */
634 else if (!(BytesReturned
) || (Write
))
636 /* Caller's input buffer is too smaller is fatal for writes */
637 Status
= STATUS_INVALID_PARAMETER
;
643 /* Does the caller want to know how big to make their buffer? */
647 *RequiredSize
= Size
;
650 /* Return final status */
659 _Out_ PULONG BytesReturned
,
663 PBL_FILE_ENTRY FileEntry
;
665 ULONG OldUnknown
, RequiredSize
;
666 BOOLEAN ChangedUnknown
;
667 BL_DEVICE_INFORMATION DeviceInfo
;
668 BL_FILE_INFORMATION fileInfo
;
670 /* Initialize variables */
671 RtlZeroMemory(&DeviceInfo
, sizeof(DeviceInfo
));
673 ChangedUnknown
= FALSE
;
675 /* Bail out if there's no buffer */
678 return STATUS_INVALID_PARAMETER
;
681 /* Bail out of the file ID is invalid */
682 if (FileId
> FileEntries
)
684 return STATUS_INVALID_PARAMETER
;
687 /* Bail out if there's no file opened for read access */
688 FileEntry
= FileTable
[FileId
];
690 !(FileEntry
->Flags
& (BL_FILE_ENTRY_OPENED
| BL_FILE_ENTRY_READ_ACCESS
)))
692 return STATUS_INVALID_PARAMETER
;
695 /* Bail out if we can't read the file's information */
696 Status
= BlFileGetInformation(FileId
, &fileInfo
);
697 if (!NT_SUCCESS(Status
))
702 /* Ensure the read attempt is valid, and fix up the size if needed */
704 Status
= FileInformationCheck(&fileInfo
,
709 if (!NT_SUCCESS(Status
))
711 /* Invalid or illegal read attempt */
715 /* Is there anything left to read after all? */
718 /* Check if flags 2 or 4 are set */
719 if ((Flags
& 2) || (Flags
& 4))
721 /* Check if this is a disk or partition device */
722 BlDeviceGetInformation(FileEntry
->DeviceId
, &DeviceInfo
);
723 if ((DeviceInfo
.DeviceType
== DiskDevice
) ||
724 (DeviceInfo
.DeviceType
== LegacyPartitionDevice
))
726 /* Check if request flags are incompatible with device flags */
727 if ((!(DeviceInfo
.BlockDeviceInfo
.Unknown
& 1) && (Flags
& 2)) ||
728 (!(DeviceInfo
.BlockDeviceInfo
.Unknown
& 2) && (Flags
& 4)))
730 /* We're going to change the device flags */
731 ChangedUnknown
= TRUE
;
733 /* Set unknown flag 1 for request flag 2 */
736 DeviceInfo
.BlockDeviceInfo
.Unknown
|= 1;
739 /* Set unknown flag 2 for request flag 4 */
742 DeviceInfo
.BlockDeviceInfo
.Unknown
|= 2;
745 /* Save the new device flags */
746 BlDeviceSetInformation(FileEntry
->DeviceId
, &DeviceInfo
);
751 /* Issue the read to the underlying file system */
752 Status
= FileEntry
->Callbacks
.Read(FileEntry
,
756 if (!NT_SUCCESS(Status
))
758 /* Don't update the bytes read on failure */
764 /* There's nothing to do, return success and 0 bytes */
765 Status
= STATUS_SUCCESS
;
772 /* Increment the number of bytes read */
773 FileEntry
->TotalBytesRead
+= RequiredSize
;
775 /* Check if the unknown flag on the device was changed during this routine */
778 /* Reset it back to its original value */
779 DeviceInfo
.BlockDeviceInfo
.Unknown
= OldUnknown
;
780 BlDeviceSetInformation(FileEntry
->DeviceId
, &DeviceInfo
);
783 /* Return the final status */
788 BlFileReadAtOffsetEx (
791 _In_ ULONGLONG ByteOffset
,
793 _Out_ PULONG BytesReturned
,
798 BL_FILE_INFORMATION FileInfo
;
800 ULONGLONG FileOffset
;
802 /* Get information on the specified file */
803 Status
= BlFileGetInformation(FileId
, &FileInfo
);
804 if (!NT_SUCCESS(Status
))
809 /* Save the current offset, and overwrite it with the one we want */
810 FileOffset
= FileInfo
.Offset
;
811 FileInfo
.Offset
= ByteOffset
;
813 /* Check the validity of the read and the actual size to read */
815 Status
= FileInformationCheck(&FileInfo
,
820 if (!NT_SUCCESS(Status
))
822 /* Bail out if the read is invalid */
823 EfiPrintf(L
"File info check failure: %lx\r\n", Status
);
827 /* Check if the offset we're requesting is not the current offset */
828 if (FileInfo
.Offset
!= FileOffset
)
830 /* Set the new offset to use */
831 Status
= BlFileSetInformation(FileId
, &FileInfo
);
832 if (!NT_SUCCESS(Status
))
834 /* Can't do much if that failed */
839 /* Do the read at the required offset now */
840 Status
= BlFileReadEx(FileId
,
845 if (!NT_SUCCESS(Status
))
847 /* The read failed -- had we modified the offset? */
848 if (FileInfo
.Offset
!= FileOffset
)
850 /* Restore the offset back to its original value */
851 FileInfo
.Offset
= FileOffset
;
852 BlFileSetInformation(FileId
, &FileInfo
);
856 /* Return the status of the read */
861 BlpFileRegisterFileSystem (
862 _In_ PBL_FS_INIT_CALLBACK InitCallback
,
863 _In_ PBL_FS_DESTROY_CALLBACK DestroyCallback
,
864 _In_ PBL_FS_MOUNT_CALLBACK MountCallback
,
865 _In_ PBL_FS_PURGE_CALLBACK PurgeCallback
,
869 PBL_FILE_SYSTEM_ENTRY FsEntry
;
872 /* Allocate an entry */
873 FsEntry
= BlMmAllocateHeap(sizeof(*FsEntry
));
876 return STATUS_NO_MEMORY
;
879 /* Initialize the file system */
880 Status
= InitCallback();
881 if (!NT_SUCCESS(Status
))
883 BlMmFreeHeap(FsEntry
);
887 /* Register the callbacks */
888 FsEntry
->MountCallback
= MountCallback
;
889 FsEntry
->DestroyCallback
= DestroyCallback
;
890 FsEntry
->InitCallback
= InitCallback
;
891 FsEntry
->PurgeCallback
= PurgeCallback
;
893 /* Insert in the right location in the list */
894 if (Flags
& BL_FS_REGISTER_AT_HEAD_FLAG
)
896 InsertHeadList(&RegisteredFileSystems
, &FsEntry
->ListEntry
);
900 InsertTailList(&RegisteredFileSystems
, &FsEntry
->ListEntry
);
904 return STATUS_SUCCESS
;
914 /* Allocate the file table */
916 FileTable
= BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY
) * FileEntries
);
919 return STATUS_INVALID_PARAMETER
;
923 RtlZeroMemory(FileTable
, sizeof(PBL_FILE_ENTRY
) * FileEntries
);
924 InitializeListHead(&RegisteredFileSystems
);
927 /* Initialize the network file system */
928 Status
= BlpFileRegisterFileSystem(NetRegisterFunctionTable
.Init
,
929 NetRegisterFunctionTable
.Destroy
,
930 NetRegisterFunctionTable
.Mount
,
931 NetRegisterFunctionTable
.Purge
,
933 if (NT_SUCCESS(Status
))
935 /* Initialize NTFS */
936 Status
= BlpFileRegisterFileSystem(NtfsRegisterFunctionTable
.Init
,
937 NtfsRegisterFunctionTable
.Destroy
,
938 NtfsRegisterFunctionTable
.Mount
,
939 NtfsRegisterFunctionTable
.Purge
,
943 if (NT_SUCCESS(Status
))
947 Status
= BlpFileRegisterFileSystem(FatRegisterFunctionTable
.Init
,
948 FatRegisterFunctionTable
.Destroy
,
949 FatRegisterFunctionTable
.Mount
,
950 FatRegisterFunctionTable
.Purge
,
955 if (NT_SUCCESS(Status
))
957 /* Initialize EXFAT (FatPlus) */
958 Status
= BlpFileRegisterFileSystem(FppRegisterFunctionTable
.Init
,
959 FppRegisterFunctionTable
.Destroy
,
960 FppRegisterFunctionTable
.Mount
,
961 FppRegisterFunctionTable
.Purge
,
965 if (NT_SUCCESS(Status
))
968 Status
= BlpFileRegisterFileSystem(WimRegisterFunctionTable
.Init
,
969 WimRegisterFunctionTable
.Destroy
,
970 WimRegisterFunctionTable
.Mount
,
971 WimRegisterFunctionTable
.Purge
,
975 if (NT_SUCCESS(Status
))
977 /* Initialize UDFS */
978 Status
= BlpFileRegisterFileSystem(UdfsRegisterFunctionTable
.Init
,
979 UdfsRegisterFunctionTable
.Destroy
,
980 UdfsRegisterFunctionTable
.Mount
,
981 UdfsRegisterFunctionTable
.Purge
,
985 if (NT_SUCCESS(Status
))
987 /* Initialize El-Torito CDFS */
988 Status
= BlpFileRegisterFileSystem(EtfsRegisterFunctionTable
.Init
,
989 EtfsRegisterFunctionTable
.Destroy
,
990 EtfsRegisterFunctionTable
.Mount
,
991 EtfsRegisterFunctionTable
.Purge
,
995 /* Destroy the file manager if any of the file systems didn't initialize */
996 if (!NT_SUCCESS(Status
))