From nobody Thu Dec 26 13:27:18 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zohomail.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1504826181228488.4832152507814; Thu, 7 Sep 2017 16:16:21 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 6265021CEB0F0; Thu, 7 Sep 2017 16:13:27 -0700 (PDT) Received: from mail.zytor.com (terminus.zytor.com [65.50.211.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 7A55B21CEB0EF for ; Thu, 7 Sep 2017 16:13:25 -0700 (PDT) Received: from localhost.localdomain ([IPv6:2804:7f4:c480:9cd0:0:0:0:2]) (authenticated bits=0) by mail.zytor.com (8.15.2/8.15.2) with ESMTPSA id v87NDnCc030918 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO); Thu, 7 Sep 2017 16:14:00 -0700 X-Original-To: edk2-devel@lists.01.org From: Paulo Alcantara To: edk2-devel@lists.01.org Date: Thu, 7 Sep 2017 20:13:22 -0300 Message-Id: <12dac8eda7858b96128e1949de5e29efed6e86be.1504825081.git.pcacjr@zytor.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: References: In-Reply-To: References: Subject: [edk2] [PATCH v5 3/6] MdeModulePkg: Initial UDF/ECMA-167 file system support X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laszlo Ersek , Eric Dong , Star Zeng MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" This patch introduces UDF file system support in EDK2. All block devices that support BlockIo and DiskIo protocols and contain a valid UDF file system - as specified by OSTA Universal Disk Format (revisions 1.02 through 2.60) - will be installed EFI_SIMPLE_FILE_SYSTEM_PROTOCOL to provide access to underlying file system. File system operations on regular, directory and symlink files are supported. Cc: Star Zeng Cc: Eric Dong Cc: Laszlo Ersek Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Paulo Alcantara Reviewed-by: Ruiyu Ni --- MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c | 185 ++ MdeModulePkg/Universal/Disk/UdfDxe/File.c | 903 ++++++++ MdeModulePkg/Universal/Disk/UdfDxe/FileName.c | 195 ++ .../Universal/Disk/UdfDxe/FileSystemOperations.c | 2447 ++++++++++++++++= ++++ MdeModulePkg/Universal/Disk/UdfDxe/Udf.c | 344 +++ MdeModulePkg/Universal/Disk/UdfDxe/Udf.h | 1244 ++++++++++ MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf | 66 + 7 files changed, 5384 insertions(+) create mode 100644 MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c create mode 100644 MdeModulePkg/Universal/Disk/UdfDxe/File.c create mode 100644 MdeModulePkg/Universal/Disk/UdfDxe/FileName.c create mode 100644 MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations= .c create mode 100644 MdeModulePkg/Universal/Disk/UdfDxe/Udf.c create mode 100644 MdeModulePkg/Universal/Disk/UdfDxe/Udf.h create mode 100644 MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c b/MdeModule= Pkg/Universal/Disk/UdfDxe/ComponentName.c new file mode 100644 index 0000000000..c58bc940b9 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c @@ -0,0 +1,185 @@ +/** @file + UEFI Component Name protocol for UDF/ECMA-167 file system driver. + + Copyright (C) 2014-2017 Paulo Alcantara + + This program and the accompanying materials are licensed and made availa= ble + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WI= THOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include "Udf.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUdfComponentNa= me =3D { + UdfComponentNameGetDriverName, + UdfComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUdfComponentNa= me2 =3D { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UdfComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UdfComponentNameGetControllerN= ame, + "en" +}; + +// +// Driver name table for Udf module. +// It is shared by the implementation of ComponentName & ComponentName2 Pr= otocol. +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUdfDriverNameTable= [] =3D { + { + "eng;en", + L"UDF File System Driver" + }, + { + NULL, + NULL + } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form o= f a + Unicode string. If the driver specified by This has a user readable name= in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver speci= fied + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the calle= r is + requesting, and it must match one of the + languages specified in SupportedLanguages.= The + number of languages supported by a driver = is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code for= mat. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specifie= d by + This and the language specified by Languag= e was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UdfComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mUdfDriverNameTable, + DriverName, + (BOOLEAN)(This =3D=3D &gUdfComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the control= ler + that is being managed by a driver. + + This function retrieves the user readable name of the controller specifi= ed by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specif= ied by + Language, then a pointer to the controller name is returned in Controlle= rName, + and EFI_SUCCESS is returned. If the driver specified by This is not cur= rently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does = not + support the language specified by Language, then EFI_UNSUPPORTED is retu= rned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to = be + returned. + + @param ChildHandle[in] The handle of the child controller to retr= ieve + the name of. This is an optional paramete= r that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus d= rivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of= a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the calle= r is + requesting, and it must match one of the + languages specified in SupportedLanguages.= The + number of languages supported by a driver = is up + to the driver writer. Language is specifie= d in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle a= nd + ChildHandle in the language specified by + Language from the point of view of the dri= ver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable n= ame in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a va= lid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not curren= tly + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UdfComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/File.c b/MdeModulePkg/Unive= rsal/Disk/UdfDxe/File.c new file mode 100644 index 0000000000..2dbcff0be4 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/UdfDxe/File.c @@ -0,0 +1,903 @@ +/** @file + Handle operations in files and directories from UDF/ECMA-167 file system= s. + + Copyright (C) 2014-2017 Paulo Alcantara + + This program and the accompanying materials are licensed and made availa= ble + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WI= THOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include "Udf.h" + +EFI_FILE_PROTOCOL gUdfFileIoOps =3D { + EFI_FILE_PROTOCOL_REVISION, + UdfOpen, + UdfClose, + UdfDelete, + UdfRead, + UdfWrite, + UdfGetPosition, + UdfSetPosition, + UdfGetInfo, + UdfSetInfo, + UdfFlush, + NULL, + NULL, + NULL, + NULL +}; + +#define _ROOT_FILE(_PrivData) (_PrivData)->Root +#define _PARENT_FILE(_PrivData) \ + ((_PrivData)->IsRootDirectory ? (_PrivData)->Root : &(_PrivData)->File) +#define _FILE(_PrivData) _PARENT_FILE(_PrivData) + +/** + Open the root directory on a volume. + + @param This Protocol instance pointer. + @param Root Returns an Open file handle for the root directory + + @retval EFI_SUCCESS The device was opened. + @retval EFI_UNSUPPORTED This volume does not support the file syste= m. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of + resources. + +**/ +EFI_STATUS +EFIAPI +UdfOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **Root + ) +{ + EFI_TPL OldTpl; + EFI_STATUS Status; + PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; + PRIVATE_UDF_FILE_DATA *PrivFileData; + + OldTpl =3D gBS->RaiseTPL (TPL_CALLBACK); + + if (This =3D=3D NULL || Root =3D=3D NULL) { + Status =3D EFI_INVALID_PARAMETER; + goto Error_Invalid_Params; + } + + PrivFsData =3D PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This); + + if (PrivFsData->OpenFiles =3D=3D 0) { + // + // There is no more open files. Read volume information again since it= was + // cleaned up on the last UdfClose() call. + // + Status =3D ReadUdfVolumeInformation ( + PrivFsData->BlockIo, + PrivFsData->DiskIo, + &PrivFsData->Volume + ); + if (EFI_ERROR (Status)) { + goto Error_Read_Udf_Volume; + } + } + + CleanupFileInformation (&PrivFsData->Root); + + // + // Find root directory file. + // + Status =3D FindRootDirectory ( + PrivFsData->BlockIo, + PrivFsData->DiskIo, + &PrivFsData->Volume, + &PrivFsData->Root + ); + if (EFI_ERROR (Status)) { + goto Error_Find_Root_Dir; + } + + PrivFileData =3D + (PRIVATE_UDF_FILE_DATA *) AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_D= ATA)); + if (PrivFileData =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Error_Alloc_Priv_File_Data; + } + + PrivFileData->Signature =3D PRIVATE_UDF_FILE_DATA_SIGNATURE; + PrivFileData->SimpleFs =3D This; + PrivFileData->Root =3D &PrivFsData->Root; + PrivFileData->IsRootDirectory =3D TRUE; + + CopyMem ((VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps, + sizeof (EFI_FILE_PROTOCOL)); + + *Root =3D &PrivFileData->FileIo; + + PrivFsData->OpenFiles++; + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; + +Error_Alloc_Priv_File_Data: + CleanupFileInformation (&PrivFsData->Root); + +Error_Find_Root_Dir: + CleanupVolumeInformation (&PrivFsData->Volume); + +Error_Read_Udf_Volume: +Error_Invalid_Params: + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + Opens a new file relative to the source file's location. + + @param This The protocol instance pointer. + @param NewHandle Returns File Handle for FileName. + @param FileName Null terminated string. "\", ".", and ".." are suppor= ted. + @param OpenMode Open mode for file. + @param Attributes Only used for EFI_FILE_MODE_CREATE. + + @retval EFI_SUCCESS The device was opened. + @retval EFI_NOT_FOUND The specified file could not be found on the + device. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_MEDIA_CHANGED The media has changed. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of + resources. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +EFIAPI +UdfOpen ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + EFI_TPL OldTpl; + EFI_STATUS Status; + PRIVATE_UDF_FILE_DATA *PrivFileData; + PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; + CHAR16 FilePath[UDF_PATH_LENGTH] =3D { 0 }; + UDF_FILE_INFO File; + PRIVATE_UDF_FILE_DATA *NewPrivFileData; + CHAR16 *TempFileName; + + OldTpl =3D gBS->RaiseTPL (TPL_CALLBACK); + + if (This =3D=3D NULL || NewHandle =3D=3D NULL || FileName =3D=3D NULL) { + Status =3D EFI_INVALID_PARAMETER; + goto Error_Invalid_Params; + } + + if (OpenMode !=3D EFI_FILE_MODE_READ) { + Status =3D EFI_WRITE_PROTECTED; + goto Error_Invalid_Params; + } + + PrivFileData =3D PRIVATE_UDF_FILE_DATA_FROM_THIS (This); + + PrivFsData =3D PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->Simpl= eFs); + + // + // Build full path + // + if (*FileName =3D=3D L'\\') { + StrCpyS (FilePath, UDF_PATH_LENGTH, FileName); + } else { + StrCpyS (FilePath, UDF_PATH_LENGTH, PrivFileData->AbsoluteFileName); + StrCatS (FilePath, UDF_PATH_LENGTH, L"\\"); + StrCatS (FilePath, UDF_PATH_LENGTH, FileName); + } + + MangleFileName (FilePath); + if (FilePath[0] =3D=3D L'\0') { + Status =3D EFI_NOT_FOUND; + goto Error_Bad_FileName; + } + + Status =3D FindFile ( + PrivFsData->BlockIo, + PrivFsData->DiskIo, + &PrivFsData->Volume, + FilePath, + _ROOT_FILE (PrivFileData), + _PARENT_FILE (PrivFileData), + &_PARENT_FILE(PrivFileData)->FileIdentifierDesc->Icb, + &File + ); + if (EFI_ERROR (Status)) { + goto Error_Find_File; + } + + NewPrivFileData =3D + (PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DA= TA)); + if (NewPrivFileData =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Error_Alloc_New_Priv_File_Data; + } + + CopyMem ((VOID *)NewPrivFileData, (VOID *)PrivFileData, + sizeof (PRIVATE_UDF_FILE_DATA)); + CopyMem ((VOID *)&NewPrivFileData->File, &File, sizeof (UDF_FILE_INFO)); + + NewPrivFileData->IsRootDirectory =3D FALSE; + + StrCpyS (NewPrivFileData->AbsoluteFileName, UDF_PATH_LENGTH, FilePath); + FileName =3D NewPrivFileData->AbsoluteFileName; + + while ((TempFileName =3D StrStr (FileName, L"\\")) !=3D NULL) { + FileName =3D TempFileName + 1; + } + + StrCpyS (NewPrivFileData->FileName, UDF_PATH_LENGTH, FileName); + + Status =3D GetFileSize ( + PrivFsData->BlockIo, + PrivFsData->DiskIo, + &PrivFsData->Volume, + &NewPrivFileData->File, + &NewPrivFileData->FileSize + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + goto Error_Get_File_Size; + } + + NewPrivFileData->FilePosition =3D 0; + ZeroMem ((VOID *)&NewPrivFileData->ReadDirInfo, + sizeof (UDF_READ_DIRECTORY_INFO)); + + *NewHandle =3D &NewPrivFileData->FileIo; + + PrivFsData->OpenFiles++; + + gBS->RestoreTPL (OldTpl); + + return Status; + +Error_Get_File_Size: + FreePool ((VOID *)NewPrivFileData); + +Error_Alloc_New_Priv_File_Data: + CleanupFileInformation (&File); + +Error_Find_File: +Error_Bad_FileName: +Error_Invalid_Params: + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + Read data from the file. + + @param This Protocol instance pointer. + @param BufferSize On input size of buffer, on output amount of data in + buffer. + @param Buffer The buffer in which data is read. + + @retval EFI_SUCCESS Data was read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains + required size. + +**/ +EFI_STATUS +EFIAPI +UdfRead ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_TPL OldTpl; + EFI_STATUS Status; + PRIVATE_UDF_FILE_DATA *PrivFileData; + PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; + UDF_VOLUME_INFO *Volume; + UDF_FILE_INFO *Parent; + UDF_READ_DIRECTORY_INFO *ReadDirInfo; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + UDF_FILE_INFO FoundFile; + UDF_FILE_IDENTIFIER_DESCRIPTOR *NewFileIdentifierDesc; + VOID *NewFileEntryData; + CHAR16 FileName[UDF_FILENAME_LENGTH] =3D { 0 }; + UINT64 FileSize; + + OldTpl =3D gBS->RaiseTPL (TPL_CALLBACK); + + if (This =3D=3D NULL || BufferSize =3D=3D NULL || (*BufferSize !=3D 0 && + Buffer =3D=3D NULL)) { + Status =3D EFI_INVALID_PARAMETER; + goto Error_Invalid_Params; + } + + PrivFileData =3D PRIVATE_UDF_FILE_DATA_FROM_THIS (This); + PrivFsData =3D PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->Simpl= eFs); + + BlockIo =3D PrivFsData->BlockIo; + DiskIo =3D PrivFsData->DiskIo; + Volume =3D &PrivFsData->Volume; + ReadDirInfo =3D &PrivFileData->ReadDirInfo; + NewFileIdentifierDesc =3D NULL; + NewFileEntryData =3D NULL; + + Parent =3D _PARENT_FILE (PrivFileData); + + Status =3D EFI_VOLUME_CORRUPTED; + + if (IS_FID_NORMAL_FILE (Parent->FileIdentifierDesc)) { + if (PrivFileData->FilePosition > PrivFileData->FileSize) { + // + // File's position is beyond the EOF + // + Status =3D EFI_DEVICE_ERROR; + goto Error_File_Beyond_The_Eof; + } + + if (PrivFileData->FilePosition =3D=3D PrivFileData->FileSize) { + *BufferSize =3D 0; + Status =3D EFI_SUCCESS; + goto Done; + } + + Status =3D ReadFileData ( + BlockIo, + DiskIo, + Volume, + Parent, + PrivFileData->FileSize, + &PrivFileData->FilePosition, + Buffer, + (UINT64 *)(UINTN)BufferSize + ); + } else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) { + if (ReadDirInfo->FidOffset =3D=3D 0 && PrivFileData->FilePosition > 0)= { + Status =3D EFI_DEVICE_ERROR; + *BufferSize =3D 0; + goto Done; + } + + for (;;) { + Status =3D ReadDirectoryEntry ( + BlockIo, + DiskIo, + Volume, + &Parent->FileIdentifierDesc->Icb, + Parent->FileEntry, + ReadDirInfo, + &NewFileIdentifierDesc + ); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_DEVICE_ERROR) { + FreePool (ReadDirInfo->DirectoryData); + ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO)); + + *BufferSize =3D 0; + Status =3D EFI_SUCCESS; + } + + goto Done; + } + + if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) { + break; + } + + FreePool ((VOID *)NewFileIdentifierDesc); + } + + Status =3D FindFileEntry ( + BlockIo, + DiskIo, + Volume, + &NewFileIdentifierDesc->Icb, + &NewFileEntryData + ); + if (EFI_ERROR (Status)) { + goto Error_Find_Fe; + } + + if (IS_FE_SYMLINK (NewFileEntryData)) { + Status =3D ResolveSymlink ( + BlockIo, + DiskIo, + Volume, + Parent, + NewFileEntryData, + &FoundFile + ); + if (EFI_ERROR (Status)) { + goto Error_Resolve_Symlink; + } + + FreePool ((VOID *)NewFileEntryData); + NewFileEntryData =3D FoundFile.FileEntry; + + Status =3D GetFileNameFromFid (NewFileIdentifierDesc, FileName); + if (EFI_ERROR (Status)) { + FreePool ((VOID *)FoundFile.FileIdentifierDesc); + goto Error_Get_FileName; + } + + FreePool ((VOID *)NewFileIdentifierDesc); + NewFileIdentifierDesc =3D FoundFile.FileIdentifierDesc; + } else { + FoundFile.FileIdentifierDesc =3D NewFileIdentifierDesc; + FoundFile.FileEntry =3D NewFileEntryData; + + Status =3D GetFileNameFromFid (FoundFile.FileIdentifierDesc, FileNam= e); + if (EFI_ERROR (Status)) { + goto Error_Get_FileName; + } + } + + Status =3D GetFileSize ( + BlockIo, + DiskIo, + Volume, + &FoundFile, + &FileSize + ); + if (EFI_ERROR (Status)) { + goto Error_Get_File_Size; + } + + Status =3D SetFileInfo ( + &FoundFile, + FileSize, + FileName, + BufferSize, + Buffer + ); + if (EFI_ERROR (Status)) { + goto Error_Set_File_Info; + } + + PrivFileData->FilePosition++; + Status =3D EFI_SUCCESS; + } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) { + Status =3D EFI_DEVICE_ERROR; + } + +Error_Set_File_Info: +Error_Get_File_Size: +Error_Get_FileName: +Error_Resolve_Symlink: + if (NewFileEntryData !=3D NULL) { + FreePool (NewFileEntryData); + } + +Error_Find_Fe: + if (NewFileIdentifierDesc !=3D NULL) { + FreePool ((VOID *)NewFileIdentifierDesc); + } + +Done: +Error_File_Beyond_The_Eof: +Error_Invalid_Params: + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + Close the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The file was closed. + +**/ +EFI_STATUS +EFIAPI +UdfClose ( + IN EFI_FILE_PROTOCOL *This + ) +{ + EFI_TPL OldTpl; + EFI_STATUS Status; + PRIVATE_UDF_FILE_DATA *PrivFileData; + PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; + + OldTpl =3D gBS->RaiseTPL (TPL_CALLBACK); + + Status =3D EFI_SUCCESS; + + if (This =3D=3D NULL) { + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + PrivFileData =3D PRIVATE_UDF_FILE_DATA_FROM_THIS (This); + + PrivFsData =3D PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->Simpl= eFs); + + if (!PrivFileData->IsRootDirectory) { + CleanupFileInformation (&PrivFileData->File); + + if (PrivFileData->ReadDirInfo.DirectoryData !=3D NULL) { + FreePool (PrivFileData->ReadDirInfo.DirectoryData); + } + } + + if (--PrivFsData->OpenFiles =3D=3D 0) { + CleanupVolumeInformation (&PrivFsData->Volume); + } + + FreePool ((VOID *)PrivFileData); + +Exit: + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + Close and delete the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The file was closed and deleted. + @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was = not + deleted. + +**/ +EFI_STATUS +EFIAPI +UdfDelete ( + IN EFI_FILE_PROTOCOL *This + ) +{ + PRIVATE_UDF_FILE_DATA *PrivFileData; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivFileData =3D PRIVATE_UDF_FILE_DATA_FROM_THIS (This); + + (VOID)PrivFileData->FileIo.Close(This); + + return EFI_WARN_DELETE_FAILURE; +} + +/** + Write data to a file. + + @param This Protocol instance pointer. + @param BufferSize On input size of buffer, on output amount of data in + buffer. + @param Buffer The buffer in which data to write. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to Open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted f= ile. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +EFIAPI +UdfWrite ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Get file's current position. + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Position was updated. + @retval EFI_UNSUPPORTED Seek request for directories is not valid. + +**/ +EFI_STATUS +EFIAPI +UdfGetPosition ( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +{ + PRIVATE_UDF_FILE_DATA *PrivFileData; + + if (This =3D=3D NULL || Position =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivFileData =3D PRIVATE_UDF_FILE_DATA_FROM_THIS (This); + + // + // As per UEFI spec, if the file handle is a directory, then the current= file + // position has no meaning and the operation is not supported. + // + if (IS_FID_DIRECTORY_FILE (&PrivFileData->File.FileIdentifierDesc)) { + return EFI_UNSUPPORTED; + } + + // + // The file is not a directory. So, return its position. + // + *Position =3D PrivFileData->FilePosition; + + return EFI_SUCCESS; +} + +/** + Set file's current position. + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Position was updated. + @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. + +**/ +EFI_STATUS +EFIAPI +UdfSetPosition ( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ) +{ + EFI_STATUS Status; + PRIVATE_UDF_FILE_DATA *PrivFileData; + UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D EFI_UNSUPPORTED; + + PrivFileData =3D PRIVATE_UDF_FILE_DATA_FROM_THIS (This); + + FileIdentifierDesc =3D PrivFileData->File.FileIdentifierDesc; + if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) { + // + // If the file handle is a directory, the _only_ position that may be = set is + // zero. This has no effect of starting the read proccess of the direc= tory + // entries over. + // + if (Position =3D=3D 0) { + PrivFileData->FilePosition =3D Position; + PrivFileData->ReadDirInfo.FidOffset =3D 0; + Status =3D EFI_SUCCESS; + } + } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) { + // + // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position = to be + // set to the EOF. + // + if (Position =3D=3D 0xFFFFFFFFFFFFFFFF) { + PrivFileData->FilePosition =3D PrivFileData->FileSize - 1; + } else { + PrivFileData->FilePosition =3D Position; + } + + Status =3D EFI_SUCCESS; + } + + return Status; +} + +/** + Get information about a file. + + @param This Protocol instance pointer. + @param InformationType Type of information to return in Buffer. + @param BufferSize On input size of buffer, on output amount of dat= a in + buffer. + @param Buffer The buffer to return data. + + @retval EFI_SUCCESS Data was returned. + @retval EFI_UNSUPPORTED InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returne= d in + BufferSize. + +**/ +EFI_STATUS +EFIAPI +UdfGetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + PRIVATE_UDF_FILE_DATA *PrivFileData; + PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; + EFI_FILE_SYSTEM_INFO *FileSystemInfo; + UINTN FileSystemInfoLength; + CHAR16 *String; + UDF_FILE_SET_DESCRIPTOR *FileSetDesc; + UINTN Index; + UINT8 *OstaCompressed; + UINT8 CompressionId; + UINT64 VolumeSize; + UINT64 FreeSpaceSize; + CHAR16 VolumeLabel[64]; + + if (This =3D=3D NULL || InformationType =3D=3D NULL || BufferSize =3D=3D= NULL || + (*BufferSize !=3D 0 && Buffer =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + PrivFileData =3D PRIVATE_UDF_FILE_DATA_FROM_THIS (This); + + PrivFsData =3D PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->Simpl= eFs); + + Status =3D EFI_UNSUPPORTED; + + if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { + Status =3D SetFileInfo ( + _FILE (PrivFileData), + PrivFileData->FileSize, + PrivFileData->FileName, + BufferSize, + Buffer + ); + } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { + String =3D VolumeLabel; + + FileSetDesc =3D PrivFsData->Volume.FileSetDescs[0]; + + OstaCompressed =3D &FileSetDesc->LogicalVolumeIdentifier[0]; + + CompressionId =3D OstaCompressed[0]; + if (!IS_VALID_COMPRESSION_ID (CompressionId)) { + return EFI_VOLUME_CORRUPTED; + } + + for (Index =3D 1; Index < 128; Index++) { + if (CompressionId =3D=3D 16) { + *String =3D *(UINT8 *)(OstaCompressed + Index) << 8; + Index++; + } else { + *String =3D 0; + } + + if (Index < 128) { + *String |=3D *(UINT8 *)(OstaCompressed + Index); + } + + // + // Unlike FID Identifiers, Logical Volume Identifier is stored in a + // NULL-terminated OSTA compressed format, so we must check for the = NULL + // character. + // + if (*String =3D=3D L'\0') { + break; + } + + String++; + } + + *String =3D L'\0'; + + FileSystemInfoLength =3D StrSize (VolumeLabel) + + sizeof (EFI_FILE_SYSTEM_INFO); + if (*BufferSize < FileSystemInfoLength) { + *BufferSize =3D FileSystemInfoLength; + return EFI_BUFFER_TOO_SMALL; + } + + FileSystemInfo =3D (EFI_FILE_SYSTEM_INFO *)Buffer; + StrCpyS (FileSystemInfo->VolumeLabel, ARRAY_SIZE (VolumeLabel), + VolumeLabel); + Status =3D GetVolumeSize ( + PrivFsData->BlockIo, + PrivFsData->DiskIo, + &PrivFsData->Volume, + &VolumeSize, + &FreeSpaceSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FileSystemInfo->Size =3D FileSystemInfoLength; + FileSystemInfo->ReadOnly =3D TRUE; + FileSystemInfo->BlockSize =3D + LV_BLOCK_SIZE (&PrivFsData->Volume, UDF_DEFAULT_LV_NUM); + FileSystemInfo->VolumeSize =3D VolumeSize; + FileSystemInfo->FreeSpace =3D FreeSpaceSize; + + *BufferSize =3D FileSystemInfoLength; + Status =3D EFI_SUCCESS; + } + + return Status; +} + +/** + Set information about a file. + + @param File Protocol instance pointer. + @param InformationType Type of information in Buffer. + @param BufferSize Size of buffer. + @param Buffer The data to write. + + @retval EFI_SUCCESS Data was set. + @retval EFI_UNSUPPORTED InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + +**/ +EFI_STATUS +EFIAPI +UdfSetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + return EFI_WRITE_PROTECTED; +} + +/** + Flush data back for the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS Data was flushed. + @retval EFI_UNSUPPORTED Writes to Open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +EFIAPI +UdfFlush ( + IN EFI_FILE_PROTOCOL *This + ) +{ + return EFI_WRITE_PROTECTED; +} diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c b/MdeModulePkg/U= niversal/Disk/UdfDxe/FileName.c new file mode 100644 index 0000000000..f73793320d --- /dev/null +++ b/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c @@ -0,0 +1,195 @@ +/** @file + Helper functions for mangling file names in UDF/ECMA-167 file systems. + + Copyright (C) 2014-2017 Paulo Alcantara + + This program and the accompanying materials are licensed and made availa= ble + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WI= THOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include "Udf.h" + +CHAR16 * +TrimString ( + IN CHAR16 *String + ) +{ + CHAR16 *TempString; + + for ( ; *String !=3D L'\0' && *String =3D=3D L' '; String++) { + ; + } + + TempString =3D String + StrLen (String) - 1; + while ((TempString >=3D String) && (*TempString =3D=3D L' ')) { + TempString--; + } + + *(TempString + 1) =3D L'\0'; + + return String; +} + +VOID +ReplaceLeft ( + IN CHAR16 *Destination, + IN CONST CHAR16 *Source + ) +{ + CONST CHAR16 *EndString; + + EndString =3D Source + StrLen (Source); + while (Source <=3D EndString) { + *Destination++ =3D *Source++; + } +} + +CHAR16 * +ExcludeTrailingBackslashes ( + IN CHAR16 *String + ) +{ + CHAR16 *TempString; + + switch (*(String + 1)) { + case L'\\': + break; + case L'\0': + default: + String++; + goto Exit; + } + + TempString =3D String; + while (*TempString !=3D L'\0' && *TempString =3D=3D L'\\') { + TempString++; + } + + if (TempString - 1 > String) { + ReplaceLeft (String + 1, TempString); + } + + String++; + +Exit: + return String; +} + +/** + Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..= ". + + @param[in] FileName Filename. + + @retval @p FileName Filename mangled. + +**/ +CHAR16 * +MangleFileName ( + IN CHAR16 *FileName + ) +{ + CHAR16 *FileNameSavedPointer; + CHAR16 *TempFileName; + UINTN BackslashesNo; + + if (FileName =3D=3D NULL || *FileName =3D=3D L'\0') { + FileName =3D NULL; + goto Exit; + } + + FileName =3D TrimString (FileName); + if (*FileName =3D=3D L'\0') { + goto Exit; + } + + if ((StrLen (FileName) > 1) && (FileName[StrLen (FileName) - 1] =3D=3D L= '\\')) { + FileName[StrLen (FileName) - 1] =3D L'\0'; + } + + FileNameSavedPointer =3D FileName; + + if (FileName[0] =3D=3D L'.') { + if (FileName[1] =3D=3D L'.') { + if (FileName[2] =3D=3D L'\0') { + goto Exit; + } else { + FileName +=3D 2; + } + } else if (FileName[1] =3D=3D L'\0') { + goto Exit; + } + } + + while (*FileName !=3D L'\0') { + if (*FileName =3D=3D L'\\') { + FileName =3D ExcludeTrailingBackslashes (FileName); + } else if (*FileName =3D=3D L'.') { + switch (*(FileName + 1)) { + case L'\0': + *FileName =3D L'\0'; + break; + case L'\\': + TempFileName =3D FileName + 1; + TempFileName =3D ExcludeTrailingBackslashes (TempFileName); + ReplaceLeft (FileName, TempFileName); + break; + case '.': + if ((*(FileName - 1) !=3D L'\\') && ((*(FileName + 2) !=3D L'\\') = || + (*(FileName + 2) !=3D L'\0'))) { + FileName++; + continue; + } + + BackslashesNo =3D 0; + TempFileName =3D FileName - 1; + while (TempFileName >=3D FileNameSavedPointer) { + if (*TempFileName =3D=3D L'\\') { + if (++BackslashesNo =3D=3D 2) { + break; + } + } + + TempFileName--; + } + + TempFileName++; + + if ((*TempFileName =3D=3D L'.') && (*(TempFileName + 1) =3D=3D L'.= ')) { + FileName +=3D 2; + } else { + if (*(FileName + 2) !=3D L'\0') { + ReplaceLeft (TempFileName, FileName + 3); + if (*(TempFileName - 1) =3D=3D L'\\') { + FileName =3D TempFileName; + ExcludeTrailingBackslashes (TempFileName - 1); + TempFileName =3D FileName; + } + } else { + *TempFileName =3D L'\0'; + } + + FileName =3D TempFileName; + } + + break; + default: + FileName++; + } + } else { + FileName++; + } + } + + FileName =3D FileNameSavedPointer; + if ((StrLen (FileName) > 1) && (FileName [StrLen (FileName) - 1] =3D=3D = L'\\')) { + FileName [StrLen (FileName) - 1] =3D L'\0'; + } + +Exit: + return FileName; +} diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c b/Md= eModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c new file mode 100644 index 0000000000..7d7f722188 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c @@ -0,0 +1,2447 @@ +/** @file + Handle on-disk format and volume structures in UDF/ECMA-167 file systems. + + Copyright (C) 2014-2017 Paulo Alcantara + + This program and the accompanying materials are licensed and made availa= ble + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WI= THOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include "Udf.h" + +EFI_STATUS +FindAnchorVolumeDescriptorPointer ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint + ) +{ + EFI_STATUS Status; + UINT32 BlockSize =3D BlockIo->Media->BlockSize; + EFI_LBA EndLBA =3D BlockIo->Media->LastBlock; + EFI_LBA DescriptorLBAs[] =3D { 256, EndLBA - 256, EndLBA, 512 }; + UINTN Index; + + for (Index =3D 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) { + Status =3D DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (DescriptorLBAs[Index], BlockSize), + sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER), + (VOID *)AnchorPoint + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Check if read LBA has a valid AVDP descriptor. + // + if (IS_AVDP (AnchorPoint)) { + return EFI_SUCCESS; + } + } + // + // No AVDP found. + // + return EFI_VOLUME_CORRUPTED; +} + +EFI_STATUS +StartMainVolumeDescriptorSequence ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint, + OUT UDF_VOLUME_INFO *Volume + ) +{ + EFI_STATUS Status; + UINT32 BlockSize; + UDF_EXTENT_AD *ExtentAd; + UINT64 StartingLsn; + UINT64 EndingLsn; + VOID *Buffer; + UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc; + UDF_PARTITION_DESCRIPTOR *PartitionDesc; + UINTN Index; + UINT32 LogicalBlockSize; + + // + // We've already found an ADVP on the volume. It contains the extent + // (MainVolumeDescriptorSequenceExtent) where the Main Volume Descriptor + // Sequence starts. Therefore, we'll look for Logical Volume Descriptors= and + // Partitions Descriptors and save them in memory, accordingly. + // + // Note also that each descriptor will be aligned on a block size (Block= Size) + // boundary, so we need to read one block at a time. + // + BlockSize =3D BlockIo->Media->BlockSize; + ExtentAd =3D &AnchorPoint->MainVolumeDescriptorSequenceExtent; + StartingLsn =3D (UINT64)ExtentAd->ExtentLocation; + EndingLsn =3D StartingLsn + DivU64x32 ( + (UINT64)ExtentAd->ExtentLength, + BlockSize + ); + + Volume->LogicalVolDescs =3D + (UDF_LOGICAL_VOLUME_DESCRIPTOR **)AllocateZeroPool (ExtentAd->ExtentLe= ngth); + if (Volume->LogicalVolDescs =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Volume->PartitionDescs =3D + (UDF_PARTITION_DESCRIPTOR **)AllocateZeroPool (ExtentAd->ExtentLength); + if (Volume->PartitionDescs =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Error_Alloc_Pds; + } + + Buffer =3D AllocateZeroPool (BlockSize); + if (Buffer =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Error_Alloc_Buf; + } + + Volume->LogicalVolDescsNo =3D 0; + Volume->PartitionDescsNo =3D 0; + + while (StartingLsn <=3D EndingLsn) { + Status =3D DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (StartingLsn, BlockSize), + BlockSize, + Buffer + ); + if (EFI_ERROR (Status)) { + goto Error_Read_Disk_Blk; + } + + if (IS_TD (Buffer)) { + // + // Found a Terminating Descriptor. Stop the sequence then. + // + break; + } + + if (IS_LVD (Buffer)) { + // + // Found a Logical Volume Descriptor. + // + LogicalVolDesc =3D + (UDF_LOGICAL_VOLUME_DESCRIPTOR *) + AllocateZeroPool (sizeof (UDF_LOGICAL_VOLUME_DESCRIPTOR)); + if (LogicalVolDesc =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Error_Alloc_Lvd; + } + + CopyMem ((VOID *)LogicalVolDesc, Buffer, + sizeof (UDF_LOGICAL_VOLUME_DESCRIPTOR)); + Volume->LogicalVolDescs[Volume->LogicalVolDescsNo++] =3D LogicalVolD= esc; + } else if (IS_PD (Buffer)) { + // + // Found a Partition Descriptor. + // + PartitionDesc =3D + (UDF_PARTITION_DESCRIPTOR *) + AllocateZeroPool (sizeof (UDF_PARTITION_DESCRIPTOR)); + if (PartitionDesc =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Error_Alloc_Pd; + } + + CopyMem ((VOID *)PartitionDesc, Buffer, + sizeof (UDF_PARTITION_DESCRIPTOR)); + Volume->PartitionDescs[Volume->PartitionDescsNo++] =3D PartitionDesc; + } + + StartingLsn++; + } + + // + // When an UDF volume (revision 2.00 or higher) contains a File Entry ra= ther + // than an Extended File Entry (which is not recommended as per spec), w= e need + // to make sure the size of a FE will be _at least_ 2048 + // (UDF_LOGICAL_SECTOR_SIZE) bytes long to keep backward compatibility. + // + LogicalBlockSize =3D LV_BLOCK_SIZE (Volume, UDF_DEFAULT_LV_NUM); + if (LogicalBlockSize >=3D UDF_LOGICAL_SECTOR_SIZE) { + Volume->FileEntrySize =3D LogicalBlockSize; + } else { + Volume->FileEntrySize =3D UDF_LOGICAL_SECTOR_SIZE; + } + + FreePool (Buffer); + + return EFI_SUCCESS; + +Error_Alloc_Pd: +Error_Alloc_Lvd: + for (Index =3D 0; Index < Volume->PartitionDescsNo; Index++) { + FreePool ((VOID *)Volume->PartitionDescs[Index]); + } + + for (Index =3D 0; Index < Volume->LogicalVolDescsNo; Index++) { + FreePool ((VOID *)Volume->LogicalVolDescs[Index]); + } + +Error_Read_Disk_Blk: + FreePool (Buffer); + +Error_Alloc_Buf: + FreePool ((VOID *)Volume->PartitionDescs); + Volume->PartitionDescs =3D NULL; + +Error_Alloc_Pds: + FreePool ((VOID *)Volume->LogicalVolDescs); + Volume->LogicalVolDescs =3D NULL; + + return Status; +} + +// +// Return a Partition Descriptor given a Long Allocation Descriptor. This = is +// necessary to calculate the right extent (LongAd) offset which is added = up +// with partition's starting location. +// +UDF_PARTITION_DESCRIPTOR * +GetPdFromLongAd ( + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd + ) +{ + UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc; + UINTN Index; + UDF_PARTITION_DESCRIPTOR *PartitionDesc; + UINT16 PartitionNum; + + LogicalVolDesc =3D Volume->LogicalVolDescs[UDF_DEFAULT_LV_NUM]; + + switch (LV_UDF_REVISION (LogicalVolDesc)) { + case 0x0102: + // + // As per UDF 1.02 specification: + // + // There shall be exactly one prevailing Logical Volume Descriptor rec= orded + // per Volume Set. The Partition Maps field shall contain only Type 1 + // Partition Maps. + // + PartitionNum =3D *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]); + break; + case 0x0150: + // + // Ensure Type 1 Partition map. Other types aren't supported in this + // implementation. + // + if (LogicalVolDesc->PartitionMaps[0] !=3D 1 || + LogicalVolDesc->PartitionMaps[1] !=3D 6) { + return NULL; + } + PartitionNum =3D *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]); + break; + case 0x0260: + // + // Fall through. + // + default: + PartitionNum =3D LongAd->ExtentLocation.PartitionReferenceNumber; + break; + } + + for (Index =3D 0; Index < Volume->PartitionDescsNo; Index++) { + PartitionDesc =3D Volume->PartitionDescs[Index]; + if (PartitionDesc->PartitionNumber =3D=3D PartitionNum) { + return PartitionDesc; + } + } + + return NULL; +} + +// +// Return logical sector number of a given Long Allocation Descriptor. +// +UINT64 +GetLongAdLsn ( + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd + ) +{ + UDF_PARTITION_DESCRIPTOR *PartitionDesc; + + PartitionDesc =3D GetPdFromLongAd (Volume, LongAd); + ASSERT (PartitionDesc !=3D NULL); + + return (UINT64)PartitionDesc->PartitionStartingLocation + + LongAd->ExtentLocation.LogicalBlockNumber; +} + +// +// Return logical sector number of a given Short Allocation Descriptor. +// +UINT64 +GetShortAdLsn ( + IN UDF_PARTITION_DESCRIPTOR *PartitionDesc, + IN UDF_SHORT_ALLOCATION_DESCRIPTOR *ShortAd + ) +{ + return (UINT64)PartitionDesc->PartitionStartingLocation + + ShortAd->ExtentPosition; +} + +// +// Find File Set Descriptor of a given Logical Volume Descriptor. +// +// The found FSD will contain the extent (LogicalVolumeContentsUse) where = our +// root directory is. +// +EFI_STATUS +FindFileSetDescriptor ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UINTN LogicalVolDescNum, + OUT UDF_FILE_SET_DESCRIPTOR *FileSetDesc + ) +{ + EFI_STATUS Status; + UINT64 Lsn; + UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc; + + LogicalVolDesc =3D Volume->LogicalVolDescs[LogicalVolDescNum]; + Lsn =3D GetLongAdLsn (Volume, &LogicalVolDesc->LogicalVolumeContentsUse); + + // + // Read extent (Long Ad). + // + Status =3D DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (Lsn, LogicalVolDesc->LogicalBlockSize), + sizeof (UDF_FILE_SET_DESCRIPTOR), + (VOID *)FileSetDesc + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check if the read extent contains a valid FSD's tag identifier. + // + if (!IS_FSD (FileSetDesc)) { + return EFI_VOLUME_CORRUPTED; + } + + return EFI_SUCCESS; +} + +// +// Get all File Set Descriptors for each Logical Volume Descriptor. +// +EFI_STATUS +GetFileSetDescriptors ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN OUT UDF_VOLUME_INFO *Volume + ) +{ + EFI_STATUS Status; + UINTN Index; + UDF_FILE_SET_DESCRIPTOR *FileSetDesc; + UINTN Count; + + Volume->FileSetDescs =3D + (UDF_FILE_SET_DESCRIPTOR **)AllocateZeroPool ( + Volume->LogicalVolDescsNo * sizeof (UDF_FILE_SET_DESCRIPTOR)); + if (Volume->FileSetDescs =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index =3D 0; Index < Volume->LogicalVolDescsNo; Index++) { + FileSetDesc =3D AllocateZeroPool (sizeof (UDF_FILE_SET_DESCRIPTOR)); + if (FileSetDesc =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Error_Alloc_Fsd; + } + + // + // Find a FSD for this LVD. + // + Status =3D FindFileSetDescriptor ( + BlockIo, + DiskIo, + Volume, + Index, + FileSetDesc + ); + if (EFI_ERROR (Status)) { + goto Error_Find_Fsd; + } + + // + // Got one. Save it. + // + Volume->FileSetDescs[Index] =3D FileSetDesc; + } + + Volume->FileSetDescsNo =3D Volume->LogicalVolDescsNo; + return EFI_SUCCESS; + +Error_Find_Fsd: + Count =3D Index + 1; + for (Index =3D 0; Index < Count; Index++) { + FreePool ((VOID *)Volume->FileSetDescs[Index]); + } + + FreePool ((VOID *)Volume->FileSetDescs); + Volume->FileSetDescs =3D NULL; + +Error_Alloc_Fsd: + return Status; +} + +// +// Read Volume and File Structure on an UDF file system. +// +EFI_STATUS +ReadVolumeFileStructure ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + OUT UDF_VOLUME_INFO *Volume + ) +{ + EFI_STATUS Status; + UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint; + + // + // Find an AVDP. + // + Status =3D FindAnchorVolumeDescriptorPointer ( + BlockIo, + DiskIo, + &AnchorPoint + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // AVDP has been found. Start MVDS. + // + Status =3D StartMainVolumeDescriptorSequence ( + BlockIo, + DiskIo, + &AnchorPoint, + Volume + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return Status; +} + +// +// Calculate length of a given File Identifier Descriptor. +// +UINT64 +GetFidDescriptorLength ( + IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc + ) +{ + return (UINT64)( + (INTN)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR, Data[0]) += 3 + + FileIdentifierDesc->LengthOfFileIdentifier + + FileIdentifierDesc->LengthOfImplementationUse) >> 2) << 2 + ); +} + +// +// Duplicate a given File Identifier Descriptor. +// +VOID +DuplicateFid ( + IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc, + OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **NewFileIdentifierDesc + ) +{ + *NewFileIdentifierDesc =3D + (UDF_FILE_IDENTIFIER_DESCRIPTOR *)AllocateCopyPool ( + GetFidDescriptorLength (FileIdentifierDesc), FileIdentifierDesc); +} + +// +// Duplicate either a given File Entry or a given Extended File Entry. +// +VOID +DuplicateFe ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN UDF_VOLUME_INFO *Volume, + IN VOID *FileEntry, + OUT VOID **NewFileEntry + ) +{ + *NewFileEntry =3D AllocateCopyPool (Volume->FileEntrySize, FileEntry); +} + +// +// Get raw data + length of a given File Entry or Extended File Entry. +// +// The file's recorded data can contain either real file content (inline) = or +// a sequence of extents (or Allocation Descriptors) which tells where fil= e's +// content is stored in. +// +// NOTE: The FE/EFE can be thought it was an inode. +// +VOID +GetFileEntryData ( + IN VOID *FileEntryData, + OUT VOID **Data, + OUT UINT64 *Length + ) +{ + UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry; + UDF_FILE_ENTRY *FileEntry; + + if (IS_EFE (FileEntryData)) { + ExtendedFileEntry =3D (UDF_EXTENDED_FILE_ENTRY *)FileEntryData; + + *Length =3D ExtendedFileEntry->InformationLength; + *Data =3D (VOID *)((UINT8 *)ExtendedFileEntry->Data + + ExtendedFileEntry->LengthOfExtendedAttributes); + } else if (IS_FE (FileEntryData)) { + FileEntry =3D (UDF_FILE_ENTRY *)FileEntryData; + + *Length =3D FileEntry->InformationLength; + *Data =3D (VOID *)((UINT8 *)FileEntry->Data + + FileEntry->LengthOfExtendedAttributes); + } +} + +// +// Get Allocation Descriptors' data information from a given FE/EFE. +// +VOID +GetAdsInformation ( + IN VOID *FileEntryData, + OUT VOID **AdsData, + OUT UINT64 *Length + ) +{ + UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry; + UDF_FILE_ENTRY *FileEntry; + + if (IS_EFE (FileEntryData)) { + ExtendedFileEntry =3D (UDF_EXTENDED_FILE_ENTRY *)FileEntryData; + + *Length =3D ExtendedFileEntry->LengthOfAllocationDescriptors; + *AdsData =3D (VOID *)((UINT8 *)ExtendedFileEntry->Data + + ExtendedFileEntry->LengthOfExtendedAttributes); + } else if (IS_FE (FileEntryData)) { + FileEntry =3D (UDF_FILE_ENTRY *)FileEntryData; + + *Length =3D FileEntry->LengthOfAllocationDescriptors; + *AdsData =3D (VOID *)((UINT8 *)FileEntry->Data + + FileEntry->LengthOfExtendedAttributes); + } +} + +// +// Read next Long Allocation Descriptor from a given file's data. +// +EFI_STATUS +GetLongAdFromAds ( + IN VOID *Data, + IN OUT UINT64 *Offset, + IN UINT64 Length, + OUT UDF_LONG_ALLOCATION_DESCRIPTOR **FoundLongAd + ) +{ + UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd; + UDF_EXTENT_FLAGS ExtentFlags; + + for (;;) { + if (*Offset >=3D Length) { + // + // No more Long Allocation Descriptors. + // + return EFI_DEVICE_ERROR; + } + + LongAd =3D + (UDF_LONG_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset); + + // + // If it's either an indirect AD (Extended Alllocation Descriptor) or = an + // allocated AD, then return it. + // + ExtentFlags =3D GET_EXTENT_FLAGS (LONG_ADS_SEQUENCE, LongAd); + if (ExtentFlags =3D=3D EXTENT_IS_NEXT_EXTENT || + ExtentFlags =3D=3D EXTENT_RECORDED_AND_ALLOCATED) { + break; + } + + // + // This AD is either not recorded but allocated, or not recorded and n= ot + // allocated. Skip it. + // + *Offset +=3D AD_LENGTH (LONG_ADS_SEQUENCE); + } + + *FoundLongAd =3D LongAd; + + return EFI_SUCCESS; +} + +// +// Read next Short Allocation Descriptor from a given file's data. +// +EFI_STATUS +GetShortAdFromAds ( + IN VOID *Data, + IN OUT UINT64 *Offset, + IN UINT64 Length, + OUT UDF_SHORT_ALLOCATION_DESCRIPTOR **FoundShortAd + ) +{ + UDF_SHORT_ALLOCATION_DESCRIPTOR *ShortAd; + UDF_EXTENT_FLAGS ExtentFlags; + + for (;;) { + if (*Offset >=3D Length) { + // + // No more Short Allocation Descriptors. + // + return EFI_DEVICE_ERROR; + } + + ShortAd =3D + (UDF_SHORT_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset); + + // + // If it's either an indirect AD (Extended Alllocation Descriptor) or = an + // allocated AD, then return it. + // + ExtentFlags =3D GET_EXTENT_FLAGS (SHORT_ADS_SEQUENCE, ShortAd); + if (ExtentFlags =3D=3D EXTENT_IS_NEXT_EXTENT || + ExtentFlags =3D=3D EXTENT_RECORDED_AND_ALLOCATED) { + break; + } + + // + // This AD is either not recorded but allocated, or not recorded and n= ot + // allocated. Skip it. + // + *Offset +=3D AD_LENGTH (SHORT_ADS_SEQUENCE); + } + + *FoundShortAd =3D ShortAd; + + return EFI_SUCCESS; +} + +// +// Get either a Short Allocation Descriptor or a Long Allocation Descripto= r from +// file's data. +// +EFI_STATUS +GetAllocationDescriptor ( + IN UDF_FE_RECORDING_FLAGS RecordingFlags, + IN VOID *Data, + IN OUT UINT64 *Offset, + IN UINT64 Length, + OUT VOID **FoundAd + ) +{ + if (RecordingFlags =3D=3D LONG_ADS_SEQUENCE) { + return GetLongAdFromAds ( + Data, + Offset, + Length, + (UDF_LONG_ALLOCATION_DESCRIPTOR **)FoundAd + ); + } else if (RecordingFlags =3D=3D SHORT_ADS_SEQUENCE) { + return GetShortAdFromAds ( + Data, + Offset, + Length, + (UDF_SHORT_ALLOCATION_DESCRIPTOR **)FoundAd + ); + } + + return EFI_DEVICE_ERROR; +} + +// +// Return logical sector number of either Short or Long Allocation Descrip= tor. +// +UINT64 +GetAllocationDescriptorLsn ( + IN UDF_FE_RECORDING_FLAGS RecordingFlags, + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb, + IN VOID *Ad + ) +{ + if (RecordingFlags =3D=3D LONG_ADS_SEQUENCE) { + return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad); + } else if (RecordingFlags =3D=3D SHORT_ADS_SEQUENCE) { + return GetShortAdLsn ( + GetPdFromLongAd (Volume, ParentIcb), + (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad + ); + } + + return 0; +} + +// +// Return offset + length of a given indirect Allocation Descriptor (AED). +// +EFI_STATUS +GetAedAdsOffset ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb, + IN UDF_FE_RECORDING_FLAGS RecordingFlags, + IN VOID *Ad, + OUT UINT64 *Offset, + OUT UINT64 *Length + ) +{ + EFI_STATUS Status; + UINT32 ExtentLength; + UINT64 Lsn; + VOID *Data; + UINT32 LogicalBlockSize; + UDF_ALLOCATION_EXTENT_DESCRIPTOR *AllocExtDesc; + + ExtentLength =3D GET_EXTENT_LENGTH (RecordingFlags, Ad); + Lsn =3D GetAllocationDescriptorLsn (RecordingFlags, + Volume, + ParentIcb, + Ad); + + Data =3D AllocatePool (ExtentLength); + if (Data =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + LogicalBlockSize =3D LV_BLOCK_SIZE (Volume, UDF_DEFAULT_LV_NUM); + + // + // Read extent. + // + Status =3D DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (Lsn, LogicalBlockSize), + ExtentLength, + Data + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Check if read extent contains a valid tag identifier for AED. + // + AllocExtDesc =3D (UDF_ALLOCATION_EXTENT_DESCRIPTOR *)Data; + if (!IS_AED (AllocExtDesc)) { + Status =3D EFI_VOLUME_CORRUPTED; + goto Exit; + } + + // + // Get AED's block offset and its length. + // + *Offset =3D MultU64x32 (Lsn, LogicalBlockSize) + + sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR); + *Length =3D AllocExtDesc->LengthOfAllocationDescriptors; + +Exit: + FreePool (Data); + + return Status; +} + +// +// Read Allocation Extent Descriptor into memory. +// +EFI_STATUS +GetAedAdsData ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb, + IN UDF_FE_RECORDING_FLAGS RecordingFlags, + IN VOID *Ad, + OUT VOID **Data, + OUT UINT64 *Length + ) +{ + EFI_STATUS Status; + UINT64 Offset; + + // + // Get AED's offset + length. + // + Status =3D GetAedAdsOffset ( + BlockIo, + DiskIo, + Volume, + ParentIcb, + RecordingFlags, + Ad, + &Offset, + Length + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Allocate buffer to read in AED's data. + // + *Data =3D AllocatePool (*Length); + if (*Data =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + Offset, + *Length, + *Data + ); +} + +// +// Function used to serialise reads of Allocation Descriptors. +// +EFI_STATUS +GrowUpBufferToNextAd ( + IN UDF_FE_RECORDING_FLAGS RecordingFlags, + IN VOID *Ad, + IN OUT VOID **Buffer, + IN UINT64 Length + ) +{ + UINT32 ExtentLength; + + ExtentLength =3D GET_EXTENT_LENGTH (RecordingFlags, Ad); + + if (*Buffer =3D=3D NULL) { + *Buffer =3D AllocatePool (ExtentLength); + if (*Buffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + *Buffer =3D ReallocatePool (Length, Length + ExtentLength, *Buffer); + if (*Buffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + return EFI_SUCCESS; +} + +// +// Read data or size of either a File Entry or an Extended File Entry. +// +EFI_STATUS +ReadFile ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb, + IN VOID *FileEntryData, + IN OUT UDF_READ_FILE_INFO *ReadFileInfo + ) +{ + EFI_STATUS Status; + UINT32 LogicalBlockSize; + VOID *Data; + UINT64 Length; + VOID *Ad; + UINT64 AdOffset; + UINT64 Lsn; + BOOLEAN DoFreeAed; + UINT64 FilePosition; + UINT64 Offset; + UINT64 DataOffset; + UINT64 BytesLeft; + UINT64 DataLength; + BOOLEAN FinishedSeeking; + UINT32 ExtentLength; + UDF_FE_RECORDING_FLAGS RecordingFlags; + + LogicalBlockSize =3D LV_BLOCK_SIZE (Volume, UDF_DEFAULT_LV_NUM); + DoFreeAed =3D FALSE; + + switch (ReadFileInfo->Flags) { + case READ_FILE_GET_FILESIZE: + case READ_FILE_ALLOCATE_AND_READ: + // + // Initialise ReadFileInfo structure for either getting file size, or + // reading file's recorded data. + // + ReadFileInfo->ReadLength =3D 0; + ReadFileInfo->FileData =3D NULL; + break; + case READ_FILE_SEEK_AND_READ: + // + // About to seek a file and/or read its data. + // + Length =3D ReadFileInfo->FileSize - ReadFileInfo->FilePosition; + if (ReadFileInfo->FileDataSize > Length) { + // + // About to read beyond the EOF -- truncate it. + // + ReadFileInfo->FileDataSize =3D Length; + } + + // + // Initialise data to start seeking and/or reading a file. + // + BytesLeft =3D ReadFileInfo->FileDataSize; + DataOffset =3D 0; + FilePosition =3D 0; + FinishedSeeking =3D FALSE; + + break; + } + + RecordingFlags =3D GET_FE_RECORDING_FLAGS (FileEntryData); + switch (RecordingFlags) { + case INLINE_DATA: + // + // There are no extents for this FE/EFE. All data is inline. + // + GetFileEntryData (FileEntryData, &Data, &Length); + + if (ReadFileInfo->Flags =3D=3D READ_FILE_GET_FILESIZE) { + ReadFileInfo->ReadLength =3D Length; + } else if (ReadFileInfo->Flags =3D=3D READ_FILE_ALLOCATE_AND_READ) { + // + // Allocate buffer for starting read data. + // + ReadFileInfo->FileData =3D AllocatePool (Length); + if (ReadFileInfo->FileData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Read all inline data into ReadFileInfo->FileData + // + CopyMem (ReadFileInfo->FileData, Data, Length); + ReadFileInfo->ReadLength =3D Length; + } else if (ReadFileInfo->Flags =3D=3D READ_FILE_SEEK_AND_READ) { + // + // If FilePosition is non-zero, seek file to FilePosition, read + // FileDataSize bytes and then updates FilePosition. + // + CopyMem ( + ReadFileInfo->FileData, + (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition), + ReadFileInfo->FileDataSize + ); + + ReadFileInfo->FilePosition +=3D ReadFileInfo->FileDataSize; + } + + break; + case LONG_ADS_SEQUENCE: + case SHORT_ADS_SEQUENCE: + // + // This FE/EFE contains a run of Allocation Descriptors. Get data + si= ze + // for start reading them out. + // + GetAdsInformation (FileEntryData, &Data, &Length); + AdOffset =3D 0; + + for (;;) { + // + // Read AD. + // + Status =3D GetAllocationDescriptor ( + RecordingFlags, + Data, + &AdOffset, + Length, + &Ad + ); + if (Status =3D=3D EFI_DEVICE_ERROR) { + Status =3D EFI_SUCCESS; + goto Done; + } + + // + // Check if AD is an indirect AD. If so, read Allocation Extent + // Descriptor and its extents (ADs). + // + if (GET_EXTENT_FLAGS (RecordingFlags, Ad) =3D=3D EXTENT_IS_NEXT_EXTE= NT) { + if (!DoFreeAed) { + DoFreeAed =3D TRUE; + } else { + FreePool (Data); + } + + Status =3D GetAedAdsData ( + BlockIo, + DiskIo, + Volume, + ParentIcb, + RecordingFlags, + Ad, + &Data, + &Length + ); + if (EFI_ERROR (Status)) { + goto Error_Get_Aed; + } + + AdOffset =3D 0; + continue; + } + + ExtentLength =3D GET_EXTENT_LENGTH (RecordingFlags, Ad); + + Lsn =3D GetAllocationDescriptorLsn (RecordingFlags, + Volume, + ParentIcb, + Ad); + + switch (ReadFileInfo->Flags) { + case READ_FILE_GET_FILESIZE: + ReadFileInfo->ReadLength +=3D ExtentLength; + break; + case READ_FILE_ALLOCATE_AND_READ: + // + // Increase FileData (if necessary) to read next extent. + // + Status =3D GrowUpBufferToNextAd ( + RecordingFlags, + Ad, + &ReadFileInfo->FileData, + ReadFileInfo->ReadLength + ); + if (EFI_ERROR (Status)) { + goto Error_Alloc_Buffer_To_Next_Ad; + } + + // + // Read extent's data into FileData. + // + Status =3D DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (Lsn, LogicalBlockSize), + ExtentLength, + (VOID *)((UINT8 *)ReadFileInfo->FileData + + ReadFileInfo->ReadLength) + ); + if (EFI_ERROR (Status)) { + goto Error_Read_Disk_Blk; + } + + ReadFileInfo->ReadLength +=3D ExtentLength; + break; + case READ_FILE_SEEK_AND_READ: + // + // Seek file first before reading in its data. + // + if (FinishedSeeking) { + Offset =3D 0; + goto Skip_File_Seek; + } + + if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) { + FilePosition +=3D ExtentLength; + goto Skip_Ad; + } + + if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) { + Offset =3D ReadFileInfo->FilePosition - FilePosition; + if (Offset < 0) { + Offset =3D -(Offset); + } + } else { + Offset =3D 0; + } + + // + // Done with seeking file. Start reading its data. + // + FinishedSeeking =3D TRUE; + + Skip_File_Seek: + // + // Make sure we don't read more data than really wanted. + // + if (ExtentLength - Offset > BytesLeft) { + DataLength =3D BytesLeft; + } else { + DataLength =3D ExtentLength - Offset; + } + + // + // Read extent's data into FileData. + // + Status =3D DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + Offset + MultU64x32 (Lsn, LogicalBlockSize), + DataLength, + (VOID *)((UINT8 *)ReadFileInfo->FileData + + DataOffset) + ); + if (EFI_ERROR (Status)) { + goto Error_Read_Disk_Blk; + } + + // + // Update current file's position. + // + DataOffset +=3D DataLength; + ReadFileInfo->FilePosition +=3D DataLength; + + BytesLeft -=3D DataLength; + if (BytesLeft =3D=3D 0) { + // + // There is no more file data to read. + // + Status =3D EFI_SUCCESS; + goto Done; + } + + break; + } + + Skip_Ad: + // + // Point to the next AD (extent). + // + AdOffset +=3D AD_LENGTH (RecordingFlags); + } + + break; + case EXTENDED_ADS_SEQUENCE: + // FIXME: Not supported. Got no volume with it, yet. + ASSERT (FALSE); + Status =3D EFI_UNSUPPORTED; + break; + } + +Done: + if (DoFreeAed) { + FreePool (Data); + } + + return Status; + +Error_Read_Disk_Blk: +Error_Alloc_Buffer_To_Next_Ad: + if (ReadFileInfo->Flags !=3D READ_FILE_SEEK_AND_READ) { + FreePool (ReadFileInfo->FileData); + } + + if (DoFreeAed) { + FreePool (Data); + } + +Error_Get_Aed: + return Status; +} + +// +// Find a file by its filename from a given Parent file. +// +EFI_STATUS +InternalFindFile ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN CHAR16 *FileName, + IN UDF_FILE_INFO *Parent, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb, + OUT UDF_FILE_INFO *File + ) +{ + EFI_STATUS Status; + UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc; + UDF_READ_DIRECTORY_INFO ReadDirInfo; + BOOLEAN Found; + CHAR16 FoundFileName[UDF_FILENAME_LENGTH]; + VOID *CompareFileEntry; + + // + // Check if parent file is really directory. + // + if (!IS_FE_DIRECTORY (Parent->FileEntry)) { + return EFI_NOT_FOUND; + } + + // + // If FileName is current file or working directory, just duplicate Pare= nt's + // FE/EFE and FID descriptors. + // + if (StrCmp (FileName, L".") =3D=3D 0) { + DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry); + DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc); + + return EFI_SUCCESS; + } + + // + // Start directory listing. + // + ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO)); + Found =3D FALSE; + + for (;;) { + Status =3D ReadDirectoryEntry ( + BlockIo, + DiskIo, + Volume, + Parent->FileIdentifierDesc ? + &Parent->FileIdentifierDesc->Icb : + Icb, + Parent->FileEntry, + &ReadDirInfo, + &FileIdentifierDesc + ); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_DEVICE_ERROR) { + Status =3D EFI_NOT_FOUND; + } + + break; + } + + if (IS_FID_PARENT_FILE (FileIdentifierDesc)) { + // + // This FID contains the location (FE/EFE) of the parent directory o= f this + // directory (Parent), and if FileName is either ".." or "\\", then = it's + // the expected FID. + // + if (StrCmp (FileName, L"..") =3D=3D 0 || StrCmp (FileName, L"\\") = =3D=3D 0) { + Found =3D TRUE; + break; + } + } else { + Status =3D GetFileNameFromFid (FileIdentifierDesc, FoundFileName); + if (EFI_ERROR (Status)) { + break; + } + + if (StrCmp (FileName, FoundFileName) =3D=3D 0) { + // + // FID has been found. Prepare to find its respective FE/EFE. + // + Found =3D TRUE; + break; + } + } + + FreePool ((VOID *)FileIdentifierDesc); + } + + if (ReadDirInfo.DirectoryData !=3D NULL) { + // + // Free all allocated resources for the directory listing. + // + FreePool (ReadDirInfo.DirectoryData); + } + + if (Found) { + Status =3D EFI_SUCCESS; + + File->FileIdentifierDesc =3D FileIdentifierDesc; + + // + // If the requested file is root directory, then the FE/EFE was already + // retrieved in UdfOpenVolume() function, thus no need to find it agai= n. + // + // Otherwise, find FE/EFE from the respective FID. + // + if (StrCmp (FileName, L"\\") !=3D 0) { + Status =3D FindFileEntry ( + BlockIo, + DiskIo, + Volume, + &FileIdentifierDesc->Icb, + &CompareFileEntry + ); + if (EFI_ERROR (Status)) { + goto Error_Find_Fe; + } + + // + // Make sure that both Parent's FE/EFE and found FE/EFE are not equa= l. + // + if (CompareMem ((VOID *)Parent->FileEntry, (VOID *)CompareFileEntry, + Volume->FileEntrySize) !=3D 0) { + File->FileEntry =3D CompareFileEntry; + } else { + FreePool ((VOID *)FileIdentifierDesc); + FreePool ((VOID *)CompareFileEntry); + Status =3D EFI_NOT_FOUND; + } + } + } + + return Status; + +Error_Find_Fe: + FreePool ((VOID *)FileIdentifierDesc); + + return Status; +} + +/** + Read volume information on a medium which contains a valid UDF file syst= em. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[out] Volume UDF volume information structure. + + @retval EFI_SUCCESS Volume information read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of reso= urces. + +**/ +EFI_STATUS +ReadUdfVolumeInformation ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + OUT UDF_VOLUME_INFO *Volume + ) +{ + EFI_STATUS Status; + + Status =3D ReadVolumeFileStructure ( + BlockIo, + DiskIo, + Volume + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D GetFileSetDescriptors ( + BlockIo, + DiskIo, + Volume + ); + if (EFI_ERROR (Status)) { + CleanupVolumeInformation (Volume); + } + + return Status; +} + +/** + Find the root directory on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[out] File Root directory file. + + @retval EFI_SUCCESS Root directory found. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lac= k of + resources. + +**/ +EFI_STATUS +FindRootDirectory ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + OUT UDF_FILE_INFO *File + ) +{ + EFI_STATUS Status; + UDF_FILE_INFO Parent; + + Status =3D FindFileEntry ( + BlockIo, + DiskIo, + Volume, + &Volume->FileSetDescs[0]->RootDirectoryIcb, + &File->FileEntry + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Parent.FileEntry =3D File->FileEntry; + Parent.FileIdentifierDesc =3D NULL; + + Status =3D FindFile ( + BlockIo, + DiskIo, + Volume, + L"\\", + NULL, + &Parent, + &Volume->FileSetDescs[0]->RootDirectoryIcb, + File + ); + if (EFI_ERROR (Status)) { + FreePool (File->FileEntry); + } + + return Status; +} + +/** + Find either a File Entry or a Extended File Entry from a given ICB. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] Icb ICB of the FID. + @param[out] FileEntry File Entry or Extended File Entry. + + @retval EFI_SUCCESS File Entry or Extended File Entry found. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack = of + resources. + +**/ +EFI_STATUS +FindFileEntry ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb, + OUT VOID **FileEntry + ) +{ + EFI_STATUS Status; + UINT64 Lsn; + UINT32 LogicalBlockSize; + + Lsn =3D GetLongAdLsn (Volume, Icb); + LogicalBlockSize =3D LV_BLOCK_SIZE (Volume, UDF_DEFAULT_LV_NUM); + + *FileEntry =3D AllocateZeroPool (Volume->FileEntrySize); + if (*FileEntry =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Read extent. + // + Status =3D DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (Lsn, LogicalBlockSize), + Volume->FileEntrySize, + *FileEntry + ); + if (EFI_ERROR (Status)) { + goto Error_Read_Disk_Blk; + } + + // + // Check if the read extent contains a valid Tag Identifier for the expe= cted + // FE/EFE. + // + if (!IS_FE (*FileEntry) && !IS_EFE (*FileEntry)) { + Status =3D EFI_VOLUME_CORRUPTED; + goto Error_Invalid_Fe; + } + + return EFI_SUCCESS; + +Error_Invalid_Fe: +Error_Read_Disk_Blk: + FreePool (*FileEntry); + + return Status; +} + +/** + Find a file given its absolute path on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] FilePath File's absolute path. + @param[in] Root Root directory file. + @param[in] Parent Parent directory file. + @param[out] File Found file. + + @retval EFI_SUCCESS @p FilePath was found. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The @p FilePath file was not found due to l= ack of + resources. + +**/ +EFI_STATUS +FindFile ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN CHAR16 *FilePath, + IN UDF_FILE_INFO *Root, + IN UDF_FILE_INFO *Parent, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb, + OUT UDF_FILE_INFO *File + ) +{ + EFI_STATUS Status; + CHAR16 FileName[UDF_FILENAME_LENGTH]; + CHAR16 *FileNamePointer; + UDF_FILE_INFO PreviousFile; + VOID *FileEntry; + + Status =3D EFI_NOT_FOUND; + + CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO)); + while (*FilePath !=3D L'\0') { + FileNamePointer =3D FileName; + while (*FilePath !=3D L'\0' && *FilePath !=3D L'\\') { + *FileNamePointer++ =3D *FilePath++; + } + + *FileNamePointer =3D L'\0'; + if (FileName[0] =3D=3D L'\0') { + // + // Open root directory. + // + if (Root =3D=3D NULL) { + // + // There is no file found for the root directory yet. So, find onl= y its + // FID by now. + // + // See UdfOpenVolume() function. + // + Status =3D InternalFindFile (BlockIo, + DiskIo, + Volume, + L"\\", + &PreviousFile, + Icb, + File); + } else { + // + // We've already a file pointer (Root) for the root directory. Dup= licate + // its FE/EFE and FID descriptors. + // + DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry); + DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc); + Status =3D EFI_SUCCESS; + } + } else { + // + // No root directory. Find filename from the current directory. + // + Status =3D InternalFindFile (BlockIo, + DiskIo, + Volume, + FileName, + &PreviousFile, + Icb, + File); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // If the found file is a symlink, then find its respective FE/EFE and + // FID descriptors. + // + if (IS_FE_SYMLINK (File->FileEntry)) { + FreePool ((VOID *)File->FileIdentifierDesc); + + FileEntry =3D File->FileEntry; + + Status =3D ResolveSymlink (BlockIo, + DiskIo, + Volume, + &PreviousFile, + FileEntry, + File); + + FreePool (FileEntry); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent, + sizeof (UDF_FILE_INFO)) !=3D 0) { + CleanupFileInformation (&PreviousFile); + } + + CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO)); + if (*FilePath !=3D L'\0' && *FilePath =3D=3D L'\\') { + FilePath++; + } + } + + return Status; +} + +/** + Read a directory entry at a time on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] ParentIcb ICB of the parent file. + @param[in] FileEntryData FE/EFE of the parent file. + @param[in out] ReadDirInfo Next read directory listing structure + information. + @param[out] FoundFid File Identifier Descriptor pointer. + + @retval EFI_SUCCESS Directory entry read. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors not support= ed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lac= k of + resources. + +**/ +EFI_STATUS +ReadDirectoryEntry ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb, + IN VOID *FileEntryData, + IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo, + OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid + ) +{ + EFI_STATUS Status; + UDF_READ_FILE_INFO ReadFileInfo; + UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc; + + if (ReadDirInfo->DirectoryData =3D=3D NULL) { + // + // The directory's recorded data has not been read yet. So let's cache= it + // into memory and the next calls won't need to read it again. + // + ReadFileInfo.Flags =3D READ_FILE_ALLOCATE_AND_READ; + + Status =3D ReadFile ( + BlockIo, + DiskIo, + Volume, + ParentIcb, + FileEntryData, + &ReadFileInfo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Fill in ReadDirInfo structure with the read directory's data inform= ation. + // + ReadDirInfo->DirectoryData =3D ReadFileInfo.FileData; + ReadDirInfo->DirectoryLength =3D ReadFileInfo.ReadLength; + } + + do { + if (ReadDirInfo->FidOffset >=3D ReadDirInfo->DirectoryLength) { + // + // There are no longer FIDs for this directory. By returning + // EFI_DEVICE_ERROR to the callee will indicate end of directory + // listening. + // + return EFI_DEVICE_ERROR; + } + + // + // Get FID for this entry. + // + FileIdentifierDesc =3D GET_FID_FROM_ADS (ReadDirInfo->DirectoryData, + ReadDirInfo->FidOffset); + // + // Update FidOffset to point to next FID. + // + ReadDirInfo->FidOffset +=3D GetFidDescriptorLength (FileIdentifierDesc= ); + } while (IS_FID_DELETED_FILE (FileIdentifierDesc)); + + DuplicateFid (FileIdentifierDesc, FoundFid); + + return EFI_SUCCESS; +} + +/** + Get a filename (encoded in OSTA-compressed format) from a File Identifier + Descriptor on an UDF volume. + + @param[in] FileIdentifierDesc File Identifier Descriptor pointer. + @param[out] FileName Decoded filename. + + @retval EFI_SUCCESS Filename decoded and read. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. +**/ +EFI_STATUS +GetFileNameFromFid ( + IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc, + OUT CHAR16 *FileName + ) +{ + UINT8 *OstaCompressed; + UINT8 CompressionId; + UINT8 Length; + UINTN Index; + + OstaCompressed =3D + (UINT8 *)( + (UINT8 *)FileIdentifierDesc->Data + + FileIdentifierDesc->LengthOfImplementationUse + ); + + CompressionId =3D OstaCompressed[0]; + if (!IS_VALID_COMPRESSION_ID (CompressionId)) { + return EFI_VOLUME_CORRUPTED; + } + + // + // Decode filename. + // + Length =3D FileIdentifierDesc->LengthOfFileIdentifier; + for (Index =3D 1; Index < Length; Index++) { + if (CompressionId =3D=3D 16) { + *FileName =3D OstaCompressed[Index++] << 8; + } else { + *FileName =3D 0; + } + + if (Index < Length) { + *FileName |=3D OstaCompressed[Index]; + } + + FileName++; + } + + *FileName =3D L'\0'; + + return EFI_SUCCESS; +} + +/** + Resolve a symlink file on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] Parent Parent file. + @param[in] FileEntryData FE/EFE structure pointer. + @param[out] File Resolved file. + + @retval EFI_SUCCESS Symlink file resolved. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors not support= ed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to la= ck of + resources. + +**/ +EFI_STATUS +ResolveSymlink ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_FILE_INFO *Parent, + IN VOID *FileEntryData, + OUT UDF_FILE_INFO *File + ) +{ + EFI_STATUS Status; + UDF_READ_FILE_INFO ReadFileInfo; + UINT8 *Data; + UINT64 Length; + UINT8 *EndData; + UDF_PATH_COMPONENT *PathComp; + UINT8 PathCompLength; + CHAR16 FileName[UDF_FILENAME_LENGTH]; + CHAR16 *C; + UINTN Index; + UINT8 CompressionId; + UDF_FILE_INFO PreviousFile; + + // + // Symlink files on UDF volumes do not contain so much data other than + // Path Components which resolves to real filenames, so it's OK to read = in + // all its data here -- usually the data will be inline with the FE/EFE = for + // lower filenames. + // + ReadFileInfo.Flags =3D READ_FILE_ALLOCATE_AND_READ; + + Status =3D ReadFile ( + BlockIo, + DiskIo, + Volume, + &Parent->FileIdentifierDesc->Icb, + FileEntryData, + &ReadFileInfo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Length =3D ReadFileInfo.ReadLength; + + Data =3D (UINT8 *)ReadFileInfo.FileData; + EndData =3D Data + Length; + + CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO)); + + for (;;) { + PathComp =3D (UDF_PATH_COMPONENT *)Data; + + PathCompLength =3D PathComp->LengthOfComponentIdentifier; + + switch (PathComp->ComponentType) { + case 1: + // + // This Path Component specifies the root directory hierarchy subjec= t to + // agreement between the originator and recipient of the medium. Ski= p it. + // + // Fall through. + // + case 2: + // + // "\\." of the current directory. Read next Path Component. + // + goto Next_Path_Component; + case 3: + // + // ".." (parent directory). Go to it. + // + CopyMem ((VOID *)FileName, L"..", 6); + break; + case 4: + // + // "." (current file). Duplicate both FE/EFE and FID of this file. + // + DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEnt= ry); + DuplicateFid (PreviousFile.FileIdentifierDesc, + &File->FileIdentifierDesc); + goto Next_Path_Component; + case 5: + // + // This Path Component identifies an object, either a file or a + // directory or an alias. + // + // Decode it from the compressed data in ComponentIdentifier and find + // respective path. + // + CompressionId =3D PathComp->ComponentIdentifier[0]; + if (!IS_VALID_COMPRESSION_ID (CompressionId)) { + return EFI_VOLUME_CORRUPTED; + } + + C =3D FileName; + for (Index =3D 1; Index < PathCompLength; Index++) { + if (CompressionId =3D=3D 16) { + *C =3D *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + + Index) << 8; + Index++; + } else { + *C =3D 0; + } + + if (Index < Length) { + *C |=3D *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Inde= x); + } + + C++; + } + + *C =3D L'\0'; + break; + } + + // + // Find file from the read filename in symlink's file data. + // + Status =3D InternalFindFile ( + BlockIo, + DiskIo, + Volume, + FileName, + &PreviousFile, + NULL, + File + ); + if (EFI_ERROR (Status)) { + goto Error_Find_File; + } + + Next_Path_Component: + Data +=3D sizeof (UDF_PATH_COMPONENT) + PathCompLength; + if (Data >=3D EndData) { + break; + } + + if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent, + sizeof (UDF_FILE_INFO)) !=3D 0) { + CleanupFileInformation (&PreviousFile); + } + + CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO)); + } + + // + // Unmap the symlink file. + // + FreePool (ReadFileInfo.FileData); + + return EFI_SUCCESS; + +Error_Find_File: + if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent, + sizeof (UDF_FILE_INFO)) !=3D 0) { + CleanupFileInformation (&PreviousFile); + } + + FreePool (ReadFileInfo.FileData); + + return Status; +} + +/** + Clean up in-memory UDF volume information. + + @param[in] Volume Volume information pointer. + +**/ +VOID +CleanupVolumeInformation ( + IN UDF_VOLUME_INFO *Volume + ) +{ + UINTN Index; + + if (Volume->LogicalVolDescs !=3D NULL) { + for (Index =3D 0; Index < Volume->LogicalVolDescsNo; Index++) { + FreePool ((VOID *)Volume->LogicalVolDescs[Index]); + } + FreePool ((VOID *)Volume->LogicalVolDescs); + } + + if (Volume->PartitionDescs !=3D NULL) { + for (Index =3D 0; Index < Volume->PartitionDescsNo; Index++) { + FreePool ((VOID *)Volume->PartitionDescs[Index]); + } + FreePool ((VOID *)Volume->PartitionDescs); + } + + if (Volume->FileSetDescs !=3D NULL) { + for (Index =3D 0; Index < Volume->FileSetDescsNo; Index++) { + FreePool ((VOID *)Volume->FileSetDescs[Index]); + } + FreePool ((VOID *)Volume->FileSetDescs); + } + + ZeroMem ((VOID *)Volume, sizeof (UDF_VOLUME_INFO)); +} + +/** + Clean up in-memory UDF file information. + + @param[in] File File information pointer. + +**/ +VOID +CleanupFileInformation ( + IN UDF_FILE_INFO *File + ) +{ + if (File->FileEntry !=3D NULL) { + FreePool (File->FileEntry); + } + if (File->FileIdentifierDesc !=3D NULL) { + FreePool ((VOID *)File->FileIdentifierDesc); + } + + ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO)); +} + +/** + Find a file from its absolute path on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] File File information structure. + @param[out] Size Size of the file. + + @retval EFI_SUCCESS File size calculated and set in @p Size. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors not support= ed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lac= k of + resources. + +**/ +EFI_STATUS +GetFileSize ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_FILE_INFO *File, + OUT UINT64 *Size + ) +{ + EFI_STATUS Status; + UDF_READ_FILE_INFO ReadFileInfo; + + ReadFileInfo.Flags =3D READ_FILE_GET_FILESIZE; + + Status =3D ReadFile ( + BlockIo, + DiskIo, + Volume, + &File->FileIdentifierDesc->Icb, + File->FileEntry, + &ReadFileInfo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *Size =3D ReadFileInfo.ReadLength; + + return EFI_SUCCESS; +} + +/** + Set information about a file on an UDF volume. + + @param[in] File File pointer. + @param[in] FileSize Size of the file. + @param[in] FileName Filename of the file. + @param[in out] BufferSize Size of the returned file infomation. + @param[out] Buffer Data of the returned file information. + + @retval EFI_SUCCESS File information set. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The file information was not set due to lac= k of + resources. + +**/ +EFI_STATUS +SetFileInfo ( + IN UDF_FILE_INFO *File, + IN UINT64 FileSize, + IN CHAR16 *FileName, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + UINTN FileInfoLength; + EFI_FILE_INFO *FileInfo; + UDF_FILE_ENTRY *FileEntry; + UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry; + + // + // Calculate the needed size for the EFI_FILE_INFO structure. + // + FileInfoLength =3D sizeof (EFI_FILE_INFO) + (FileName ? + StrSize (FileName) : + sizeof (CHAR16)); + if (*BufferSize < FileInfoLength) { + // + // The given Buffer has no size enough for EFI_FILE_INFO structure. + // + *BufferSize =3D FileInfoLength; + return EFI_BUFFER_TOO_SMALL; + } + + // + // Buffer now contains room enough to store EFI_FILE_INFO structure. + // Now, fill it in with all necessary information about the file. + // + FileInfo =3D (EFI_FILE_INFO *)Buffer; + FileInfo->Size =3D FileInfoLength; + FileInfo->Attribute &=3D ~EFI_FILE_VALID_ATTR; + FileInfo->Attribute |=3D EFI_FILE_READ_ONLY; + + if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) { + FileInfo->Attribute |=3D EFI_FILE_DIRECTORY; + } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) { + FileInfo->Attribute |=3D EFI_FILE_ARCHIVE; + } + + if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) { + FileInfo->Attribute |=3D EFI_FILE_HIDDEN; + } + + if (IS_FE (File->FileEntry)) { + FileEntry =3D (UDF_FILE_ENTRY *)File->FileEntry; + + // + // Check if FE has the system attribute set. + // + if (FileEntry->IcbTag.Flags & (1 << 10)) { + FileInfo->Attribute |=3D EFI_FILE_SYSTEM; + } + + FileInfo->FileSize =3D FileSize; + FileInfo->PhysicalSize =3D FileSize; + + FileInfo->CreateTime.Year =3D FileEntry->AccessTime.Year; + FileInfo->CreateTime.Month =3D FileEntry->AccessTime.Month; + FileInfo->CreateTime.Day =3D FileEntry->AccessTime.Day; + FileInfo->CreateTime.Hour =3D FileEntry->AccessTime.Hour; + FileInfo->CreateTime.Minute =3D FileEntry->AccessTime.Second; + FileInfo->CreateTime.Second =3D FileEntry->AccessTime.Second; + FileInfo->CreateTime.Nanosecond =3D + FileEntry->AccessTime.HundredsOfMicrose= conds; + + FileInfo->LastAccessTime.Year =3D + FileEntry->AccessTime.Year; + FileInfo->LastAccessTime.Month =3D + FileEntry->AccessTime.Month; + FileInfo->LastAccessTime.Day =3D + FileEntry->AccessTime.Day; + FileInfo->LastAccessTime.Hour =3D + FileEntry->AccessTime.Hour; + FileInfo->LastAccessTime.Minute =3D + FileEntry->AccessTime.Minute; + FileInfo->LastAccessTime.Second =3D + FileEntry->AccessTime.Second; + FileInfo->LastAccessTime.Nanosecond =3D + FileEntry->AccessTime.HundredsOfMicrose= conds; + } else if (IS_EFE (File->FileEntry)) { + ExtendedFileEntry =3D (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry; + + // + // Check if EFE has the system attribute set. + // + if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) { + FileInfo->Attribute |=3D EFI_FILE_SYSTEM; + } + + FileInfo->FileSize =3D FileSize; + FileInfo->PhysicalSize =3D FileSize; + + FileInfo->CreateTime.Year =3D ExtendedFileEntry->CreationTime.Y= ear; + FileInfo->CreateTime.Month =3D ExtendedFileEntry->CreationTime.M= onth; + FileInfo->CreateTime.Day =3D ExtendedFileEntry->CreationTime.D= ay; + FileInfo->CreateTime.Hour =3D ExtendedFileEntry->CreationTime.H= our; + FileInfo->CreateTime.Minute =3D ExtendedFileEntry->CreationTime.S= econd; + FileInfo->CreateTime.Second =3D ExtendedFileEntry->CreationTime.S= econd; + FileInfo->CreateTime.Nanosecond =3D + ExtendedFileEntry->AccessTime.HundredsOfMicrose= conds; + + FileInfo->LastAccessTime.Year =3D + ExtendedFileEntry->AccessTime.Year; + FileInfo->LastAccessTime.Month =3D + ExtendedFileEntry->AccessTime.Month; + FileInfo->LastAccessTime.Day =3D + ExtendedFileEntry->AccessTime.Day; + FileInfo->LastAccessTime.Hour =3D + ExtendedFileEntry->AccessTime.Hour; + FileInfo->LastAccessTime.Minute =3D + ExtendedFileEntry->AccessTime.Minute; + FileInfo->LastAccessTime.Second =3D + ExtendedFileEntry->AccessTime.Second; + FileInfo->LastAccessTime.Nanosecond =3D + ExtendedFileEntry->AccessTime.HundredsOfMicrose= conds; + } + + FileInfo->CreateTime.TimeZone =3D EFI_UNSPECIFIED_TIMEZONE; + FileInfo->CreateTime.Daylight =3D EFI_TIME_ADJUST_DAYLIGHT; + FileInfo->LastAccessTime.TimeZone =3D EFI_UNSPECIFIED_TIMEZONE; + FileInfo->LastAccessTime.Daylight =3D EFI_TIME_ADJUST_DAYLIGHT; + + CopyMem ((VOID *)&FileInfo->ModificationTime, + (VOID *)&FileInfo->LastAccessTime, + sizeof (EFI_TIME)); + + if (FileName !=3D NULL) { + StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName); + } else { + FileInfo->FileName[0] =3D '\0'; + } + + *BufferSize =3D FileInfoLength; + + return EFI_SUCCESS; +} + +/** + Get volume and free space size information of an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[out] VolumeSize Volume size. + @param[out] FreeSpaceSize Free space size. + + @retval EFI_SUCCESS Volume and free space size calculated. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The volume and free space size were not + calculated due to lack of resources. + +**/ +EFI_STATUS +GetVolumeSize ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + OUT UINT64 *VolumeSize, + OUT UINT64 *FreeSpaceSize + ) +{ + UDF_EXTENT_AD ExtentAd; + UINT32 LogicalBlockSize; + UINT64 Lsn; + EFI_STATUS Status; + UDF_LOGICAL_VOLUME_INTEGRITY *LogicalVolInt; + UINTN Index; + UINTN Length; + UINT32 LsnsNo; + + *VolumeSize =3D 0; + *FreeSpaceSize =3D 0; + + for (Index =3D 0; Index < Volume->LogicalVolDescsNo; Index++) { + CopyMem ((VOID *)&ExtentAd, + (VOID *)&Volume->LogicalVolDescs[Index]->IntegritySequenceExt= ent, + sizeof (UDF_EXTENT_AD)); + if (ExtentAd.ExtentLength =3D=3D 0) { + continue; + } + + LogicalBlockSize =3D LV_BLOCK_SIZE (Volume, Index); + + Read_Next_Sequence: + LogicalVolInt =3D (UDF_LOGICAL_VOLUME_INTEGRITY *) + AllocatePool (ExtentAd.ExtentLength); + if (LogicalVolInt =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Lsn =3D (UINT64)ExtentAd.ExtentLocation; + + Status =3D DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (Lsn, LogicalBlockSize), + ExtentAd.ExtentLength, + (VOID *)LogicalVolInt + ); + if (EFI_ERROR (Status)) { + FreePool ((VOID *)LogicalVolInt); + return Status; + } + + if (!IS_LVID (LogicalVolInt)) { + FreePool ((VOID *)LogicalVolInt); + return EFI_VOLUME_CORRUPTED; + } + + Length =3D LogicalVolInt->NumberOfPartitions; + for (Index =3D 0; Index < Length; Index +=3D sizeof (UINT32)) { + LsnsNo =3D *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index); + if (LsnsNo =3D=3D 0xFFFFFFFFUL) { + // + // Size not specified. + // + continue; + } + + *FreeSpaceSize +=3D MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize); + } + + Length =3D (LogicalVolInt->NumberOfPartitions * sizeof (UINT32)) << 1; + for (; Index < Length; Index +=3D sizeof (UINT32)) { + LsnsNo =3D *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index); + if (LsnsNo =3D=3D 0xFFFFFFFFUL) { + // + // Size not specified. + // + continue; + } + + *VolumeSize +=3D MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize); + } + + CopyMem ((VOID *)&ExtentAd,(VOID *)&LogicalVolInt->NextIntegrityExtent, + sizeof (UDF_EXTENT_AD)); + if (ExtentAd.ExtentLength > 0) { + FreePool ((VOID *)LogicalVolInt); + goto Read_Next_Sequence; + } + + FreePool ((VOID *)LogicalVolInt); + } + + return EFI_SUCCESS; +} + +/** + Seek a file and read its data into memory on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] File File information structure. + @param[in] FileSize Size of the file. + @param[in out] FilePosition File position. + @param[in out] Buffer File data. + @param[in out] BufferSize Read size. + + @retval EFI_SUCCESS File seeked and read. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors not support= ed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due t= o lack + of resources. + +**/ +EFI_STATUS +ReadFileData ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_FILE_INFO *File, + IN UINT64 FileSize, + IN OUT UINT64 *FilePosition, + IN OUT VOID *Buffer, + IN OUT UINT64 *BufferSize + ) +{ + EFI_STATUS Status; + UDF_READ_FILE_INFO ReadFileInfo; + + ReadFileInfo.Flags =3D READ_FILE_SEEK_AND_READ; + ReadFileInfo.FilePosition =3D *FilePosition; + ReadFileInfo.FileData =3D Buffer; + ReadFileInfo.FileDataSize =3D *BufferSize; + ReadFileInfo.FileSize =3D FileSize; + + Status =3D ReadFile ( + BlockIo, + DiskIo, + Volume, + &File->FileIdentifierDesc->Icb, + File->FileEntry, + &ReadFileInfo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *BufferSize =3D ReadFileInfo.FileDataSize; + *FilePosition =3D ReadFileInfo.FilePosition; + + return EFI_SUCCESS; +} + +/** + Check if ControllerHandle supports an UDF file system. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to test. + + @retval EFI_SUCCESS UDF file system found. + @retval EFI_UNSUPPORTED UDF file system not found. + +**/ +EFI_STATUS +SupportUdfFileSystem ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode; + EFI_GUID *VendorDefinedGuid; + EFI_GUID UdfDevPathGuid =3D EFI_UDF_DEVICE_PATH_GUID; + + // + // Open Device Path protocol on ControllerHandle + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&DevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status =3D EFI_UNSUPPORTED; + + // + // Get last Device Path node + // + LastDevicePathNode =3D NULL; + DevicePathNode =3D DevicePath; + while (!IsDevicePathEnd (DevicePathNode)) { + LastDevicePathNode =3D DevicePathNode; + DevicePathNode =3D NextDevicePathNode (DevicePathNode); + } + // + // Check if last Device Path node contains a Vendor-Defined Media Device= Path + // of an UDF file system. + // + if (LastDevicePathNode !=3D NULL && + DevicePathType (LastDevicePathNode) =3D=3D MEDIA_DEVICE_PATH && + DevicePathSubType (LastDevicePathNode) =3D=3D MEDIA_VENDOR_DP) { + VendorDefinedGuid =3D (EFI_GUID *)((UINTN)LastDevicePathNode + + OFFSET_OF (VENDOR_DEVICE_PATH, Guid)); + if (CompareGuid (VendorDefinedGuid, &UdfDevPathGuid)) { + Status =3D EFI_SUCCESS; + } + } + + // + // Close Device Path protocol on ControllerHandle + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return Status; +} diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c b/MdeModulePkg/Univer= sal/Disk/UdfDxe/Udf.c new file mode 100644 index 0000000000..49dc7077b7 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c @@ -0,0 +1,344 @@ +/** @file + UDF/ECMA-167 file system driver. + + Copyright (C) 2014-2017 Paulo Alcantara + + This program and the accompanying materials are licensed and made availa= ble + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WI= THOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include "Udf.h" + +// +// UDF filesystem driver's Global Variables. +// +EFI_DRIVER_BINDING_PROTOCOL gUdfDriverBinding =3D { + UdfDriverBindingSupported, + UdfDriverBindingStart, + UdfDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gUdfSimpleFsTemplate =3D { + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION, + UdfOpenVolume +}; + +/** + Test to see if this driver supports ControllerHandle. Any ControllerHand= le + than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be + supported. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to test. + @param[in] RemainingDevicePath Optional parameter use to pick a specific + child device to start. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_ALREADY_STARTED This driver is already running on this devic= e. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +UdfDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_DISK_IO_PROTOCOL *DiskIo; + + // + // Open DiskIo protocol on ControllerHandle + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID **)&DiskIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Close DiskIo protocol on ControllerHandle + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + // + // Test whether ControllerHandle supports BlockIo protocol + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + return Status; +} + +/** + Start this driver on ControllerHandle by opening a Block IO or a Block I= O2 + or both, and Disk IO protocol, reading Device Path, and creating a child + handle with a Disk IO and device path protocol. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind driver to + @param[in] RemainingDevicePath Optional parameter use to pick a specif= ic + child device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHandle. + @retval EFI_ALREADY_STARTED This driver is already running on + ControllerHandle. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +UdfDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_TPL OldTpl; + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; + + OldTpl =3D gBS->RaiseTPL (TPL_CALLBACK); + + // + // Open BlockIo protocol on ControllerHandle + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + (VOID **)&BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + + // + // Open DiskIo protocol on ControllerHandle + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID **)&DiskIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + ASSERT_EFI_ERROR (Status); + + // + // Check if ControllerHandle supports an UDF file system + // + Status =3D SupportUdfFileSystem (This, ControllerHandle); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Initialize private file system structure + // + PrivFsData =3D + (PRIVATE_UDF_SIMPLE_FS_DATA *) + AllocateZeroPool (sizeof (PRIVATE_UDF_SIMPLE_FS_DATA)); + if (PrivFsData =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Create new child handle + // + PrivFsData->Signature =3D PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE; + PrivFsData->BlockIo =3D BlockIo; + PrivFsData->DiskIo =3D DiskIo; + PrivFsData->Handle =3D ControllerHandle; + + // + // Set up SimpleFs protocol + // + CopyMem ((VOID *)&PrivFsData->SimpleFs, (VOID *)&gUdfSimpleFsTemplate, + sizeof (EFI_SIMPLE_FILE_SYSTEM_PROTOCOL)); + + // + // Install child handle + // + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &PrivFsData->Handle, + &gEfiSimpleFileSystemProtocolGuid, + &PrivFsData->SimpleFs, + NULL + ); + +Exit: + if (EFI_ERROR (Status)) { + // + // Close DiskIo protocol on ControllerHandle + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + // + // Close BlockIo protocol on ControllerHandle + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + Stop this driver on ControllerHandle. Support stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to stop driver on + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If num= ber of + children is zero stop the entire bus driver. + @param ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval other This driver was not removed from this device + +**/ +EFI_STATUS +EFIAPI +UdfDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs; + + // + // Open SimpleFs protocol on ControllerHandle + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID **)&SimpleFs, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + PrivFsData =3D PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (SimpleFs); + + // + // Uninstall child handle + // + Status =3D gBS->UninstallMultipleProtocolInterfaces ( + PrivFsData->Handle, + &gEfiSimpleFileSystemProtocolGuid, + &PrivFsData->SimpleFs, + NULL + ); + + // + // Check if there's any open file. If so, clean them up. + // + if (PrivFsData->OpenFiles > 0) { + CleanupVolumeInformation (&PrivFsData->Volume); + } + + FreePool ((VOID *)PrivFsData); + } + + if (!EFI_ERROR (Status)) { + // + // Close DiskIo protocol on ControllerHandle + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + // + // Close BlockIo protocol on ControllerHandle + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + + return Status; +} + +/** + The user Entry Point for UDF file system driver. The user code starts wi= th + this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI imag= e. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry po= int. + +**/ +EFI_STATUS +EFIAPI +InitializeUdf ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status =3D EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gUdfDriverBinding, + ImageHandle, + &gUdfComponentName, + &gUdfComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h b/MdeModulePkg/Univer= sal/Disk/UdfDxe/Udf.h new file mode 100644 index 0000000000..240d420ff5 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h @@ -0,0 +1,1244 @@ +/** @file + UDF/ECMA-167 file system driver. + + Copyright (C) 2014-2017 Paulo Alcantara + + This program and the accompanying materials are licensed and made availa= ble + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WI= THOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#ifndef _UDF_H_ +#define _UDF_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// +// C5BD4D42-1A76-4996-8956-73CDA326CD0A +// +#define EFI_UDF_DEVICE_PATH_GUID \ + { 0xC5BD4D42, 0x1A76, 0x4996, \ + { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \ + } + +#define UDF_DEFAULT_LV_NUM 0 + +#define IS_PVD(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 1)) +#define IS_PD(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 5)) +#define IS_LVD(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 6)) +#define IS_TD(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 8)) +#define IS_FSD(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 256)) +#define IS_FE(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 261)) +#define IS_EFE(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 266)) +#define IS_FID(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 257)) +#define IS_AED(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 258)) +#define IS_LVID(_Pointer) \ + ((BOOLEAN)(_GET_TAG_ID (_Pointer) =3D=3D 9)) + +#define _GET_FILETYPE(_Pointer) \ + (IS_FE (_Pointer) ? \ + (((UDF_FILE_ENTRY *)(_Pointer))->IcbTag.FileType) \ + : \ + (((UDF_EXTENDED_FILE_ENTRY *)(_Pointer))->IcbTag.FileType)) + +#define IS_FE_DIRECTORY(_Pointer) \ + ((BOOLEAN)(_GET_FILETYPE (_Pointer) =3D=3D 4)) +#define IS_FE_STANDARD_FILE(_Pointer) \ + ((BOOLEAN)(_GET_FILETYPE (_Pointer) =3D=3D 5)) +#define IS_FE_SYMLINK(_Pointer) \ + ((BOOLEAN)(_GET_FILETYPE (_Pointer) =3D=3D 12)) + +#define HIDDEN_FILE (1 << 0) +#define DIRECTORY_FILE (1 << 1) +#define DELETED_FILE (1 << 2) +#define PARENT_FILE (1 << 3) + +#define _GET_FILE_CHARS(_Pointer) \ + (((UDF_FILE_IDENTIFIER_DESCRIPTOR *)(_Pointer))->FileCharacteristics) + +#define IS_FID_HIDDEN_FILE(_Pointer) \ + ((BOOLEAN)(_GET_FILE_CHARS (_Pointer) & HIDDEN_FILE)) +#define IS_FID_DIRECTORY_FILE(_Pointer) \ + ((BOOLEAN)(_GET_FILE_CHARS (_Pointer) & DIRECTORY_FILE)) +#define IS_FID_DELETED_FILE(_Pointer) \ + ((BOOLEAN)(_GET_FILE_CHARS (_Pointer) & DELETED_FILE)) +#define IS_FID_PARENT_FILE(_Pointer) \ + ((BOOLEAN)(_GET_FILE_CHARS (_Pointer) & PARENT_FILE)) +#define IS_FID_NORMAL_FILE(_Pointer) \ + ((BOOLEAN)(!IS_FID_DIRECTORY_FILE (_Pointer) && \ + !IS_FID_PARENT_FILE (_Pointer))) + +typedef enum { + SHORT_ADS_SEQUENCE, + LONG_ADS_SEQUENCE, + EXTENDED_ADS_SEQUENCE, + INLINE_DATA +} UDF_FE_RECORDING_FLAGS; + +#define GET_FE_RECORDING_FLAGS(_Fe) \ + ((UDF_FE_RECORDING_FLAGS)((UDF_ICB_TAG *)( \ + (UINT8 *)(_Fe) + \ + sizeof (UDF_DESCRIPTOR_TAG)))->Flags & 0x07) + +typedef enum { + EXTENT_RECORDED_AND_ALLOCATED, + EXTENT_NOT_RECORDED_BUT_ALLOCATED, + EXTENT_NOT_RECORDED_NOT_ALLOCATED, + EXTENT_IS_NEXT_EXTENT, +} UDF_EXTENT_FLAGS; + +#define AD_LENGTH(_RecFlags) \ + ((_RecFlags) =3D=3D SHORT_ADS_SEQUENCE ? \ + ((UINT64)(sizeof (UDF_SHORT_ALLOCATION_DESCRIPTOR))) : \ + ((UINT64)(sizeof (UDF_LONG_ALLOCATION_DESCRIPTOR)))) + +#define GET_EXTENT_FLAGS(_RecFlags, _Ad) \ + ((_RecFlags) =3D=3D SHORT_ADS_SEQUENCE ? \ + ((UDF_EXTENT_FLAGS)((((UDF_SHORT_ALLOCATION_DESCRIPTOR *)(_Ad))->Extent= Length >> \ + 30) & 0x3)) : \ + ((UDF_EXTENT_FLAGS)((((UDF_LONG_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentL= ength >> \ + 30) & 0x3))) + +#define GET_EXTENT_LENGTH(_RecFlags, _Ad) \ + ((_RecFlags) =3D=3D SHORT_ADS_SEQUENCE ? \ + ((UINT32)((((UDF_SHORT_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength & \ + ~0xC0000000UL))) : \ + ((UINT32)((((UDF_LONG_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength & \ + ~0xC0000000UL)))) + +#define UDF_FILENAME_LENGTH 128 +#define UDF_PATH_LENGTH 512 + +#define GET_FID_FROM_ADS(_Data, _Offs) \ + ((UDF_FILE_IDENTIFIER_DESCRIPTOR *)((UINT8 *)(_Data) + (_Offs))) + +#define IS_VALID_COMPRESSION_ID(_CompId) \ + ((BOOLEAN)((_CompId) =3D=3D 8 || (_CompId) =3D=3D 16)) + +#define LV_BLOCK_SIZE(_Vol, _LvNum) \ + (_Vol)->LogicalVolDescs[(_LvNum)]->LogicalBlockSize + +#define UDF_STANDARD_IDENTIFIER_LENGTH 5 + +#define LV_UDF_REVISION(_Lv) \ + *(UINT16 *)(UINTN)(_Lv)->DomainIdentifier.IdentifierSuffix + +#pragma pack(1) + +typedef struct { + UINT8 StandardIdentifier[UDF_STANDARD_IDENTIFIER_LENGTH]; +} UDF_STANDARD_IDENTIFIER; + +#pragma pack() + +typedef enum { + READ_FILE_GET_FILESIZE, + READ_FILE_ALLOCATE_AND_READ, + READ_FILE_SEEK_AND_READ, +} UDF_READ_FILE_FLAGS; + +typedef struct { + VOID *FileData; + UDF_READ_FILE_FLAGS Flags; + UINT64 FileDataSize; + UINT64 FilePosition; + UINT64 FileSize; + UINT64 ReadLength; +} UDF_READ_FILE_INFO; + +#pragma pack(1) + +typedef struct { + UINT8 CharacterSetType; + UINT8 CharacterSetInfo[63]; +} UDF_CHAR_SPEC; + +typedef struct { + UINT8 Flags; + UINT8 Identifier[23]; + UINT8 IdentifierSuffix[8]; +} UDF_ENTITY_ID; + +typedef struct { + UINT16 TypeAndTimezone; + INT16 Year; + UINT8 Month; + UINT8 Day; + UINT8 Hour; + UINT8 Minute; + UINT8 Second; + UINT8 Centiseconds; + UINT8 HundredsOfMicroseconds; + UINT8 Microseconds; +} UDF_TIMESTAMP; + +typedef struct { + UINT32 LogicalBlockNumber; + UINT16 PartitionReferenceNumber; +} UDF_LB_ADDR; + +typedef struct { + UINT32 ExtentLength; + UDF_LB_ADDR ExtentLocation; + UINT8 ImplementationUse[6]; +} UDF_LONG_ALLOCATION_DESCRIPTOR; + +typedef struct { + UDF_DESCRIPTOR_TAG DescriptorTag; + UINT32 PrevAllocationExtentDescriptor; + UINT32 LengthOfAllocationDescriptors; +} UDF_ALLOCATION_EXTENT_DESCRIPTOR; + +typedef struct { + UINT8 StructureType; + UINT8 StandardIdentifier[UDF_STANDARD_IDENTIFIER_LENGT= H]; + UINT8 StructureVersion; + UINT8 Reserved; + UINT8 StructureData[2040]; +} UDF_VOLUME_DESCRIPTOR; + +typedef struct { + UDF_DESCRIPTOR_TAG DescriptorTag; + UINT32 VolumeDescriptorSequenceNumber; + UINT16 PartitionFlags; + UINT16 PartitionNumber; + UDF_ENTITY_ID PartitionContents; + UINT8 PartitionContentsUse[128]; + UINT32 AccessType; + UINT32 PartitionStartingLocation; + UINT32 PartitionLength; + UDF_ENTITY_ID ImplementationIdentifier; + UINT8 ImplementationUse[128]; + UINT8 Reserved[156]; +} UDF_PARTITION_DESCRIPTOR; + +typedef struct { + UDF_DESCRIPTOR_TAG DescriptorTag; + UINT32 VolumeDescriptorSequenceNumber; + UDF_CHAR_SPEC DescriptorCharacterSet; + UINT8 LogicalVolumeIdentifier[128]; + UINT32 LogicalBlockSize; + UDF_ENTITY_ID DomainIdentifier; + UDF_LONG_ALLOCATION_DESCRIPTOR LogicalVolumeContentsUse; + UINT32 MapTableLength; + UINT32 NumberOfPartitionMaps; + UDF_ENTITY_ID ImplementationIdentifier; + UINT8 ImplementationUse[128]; + UDF_EXTENT_AD IntegritySequenceExtent; + UINT8 PartitionMaps[6]; +} UDF_LOGICAL_VOLUME_DESCRIPTOR; + +typedef struct { + UDF_DESCRIPTOR_TAG DescriptorTag; + UDF_TIMESTAMP RecordingDateTime; + UINT32 IntegrityType; + UDF_EXTENT_AD NextIntegrityExtent; + UINT8 LogicalVolumeContentsUse[32]; + UINT32 NumberOfPartitions; + UINT32 LengthOfImplementationUse; + UINT8 Data[0]; +} UDF_LOGICAL_VOLUME_INTEGRITY; + +typedef struct { + UDF_DESCRIPTOR_TAG DescriptorTag; + UDF_TIMESTAMP RecordingDateAndTime; + UINT16 InterchangeLevel; + UINT16 MaximumInterchangeLevel; + UINT32 CharacterSetList; + UINT32 MaximumCharacterSetList; + UINT32 FileSetNumber; + UINT32 FileSetDescriptorNumber; + UDF_CHAR_SPEC LogicalVolumeIdentifierCharacterSet; + UINT8 LogicalVolumeIdentifier[128]; + UDF_CHAR_SPEC FileSetCharacterSet; + UINT8 FileSetIdentifier[32]; + UINT8 CopyrightFileIdentifier[32]; + UINT8 AbstractFileIdentifier[32]; + UDF_LONG_ALLOCATION_DESCRIPTOR RootDirectoryIcb; + UDF_ENTITY_ID DomainIdentifier; + UDF_LONG_ALLOCATION_DESCRIPTOR NextExtent; + UDF_LONG_ALLOCATION_DESCRIPTOR SystemStreamDirectoryIcb; + UINT8 Reserved[32]; +} UDF_FILE_SET_DESCRIPTOR; + +typedef struct { + UINT32 ExtentLength; + UINT32 ExtentPosition; +} UDF_SHORT_ALLOCATION_DESCRIPTOR; + +typedef struct { + UDF_DESCRIPTOR_TAG DescriptorTag; + UINT16 FileVersionNumber; + UINT8 FileCharacteristics; + UINT8 LengthOfFileIdentifier; + UDF_LONG_ALLOCATION_DESCRIPTOR Icb; + UINT16 LengthOfImplementationUse; + UINT8 Data[0]; +} UDF_FILE_IDENTIFIER_DESCRIPTOR; + +typedef struct { + UINT32 PriorRecordNumberOfDirectEntries; + UINT16 StrategyType; + UINT16 StrategyParameter; + UINT16 MaximumNumberOfEntries; + UINT8 Reserved; + UINT8 FileType; + UDF_LB_ADDR ParentIcbLocation; + UINT16 Flags; +} UDF_ICB_TAG; + +typedef struct { + UDF_DESCRIPTOR_TAG DescriptorTag; + UDF_ICB_TAG IcbTag; + UINT32 Uid; + UINT32 Gid; + UINT32 Permissions; + UINT16 FileLinkCount; + UINT8 RecordFormat; + UINT8 RecordDisplayAttributes; + UINT32 RecordLength; + UINT64 InformationLength; + UINT64 LogicalBlocksRecorded; + UDF_TIMESTAMP AccessTime; + UDF_TIMESTAMP ModificationTime; + UDF_TIMESTAMP AttributeTime; + UINT32 CheckPoint; + UDF_LONG_ALLOCATION_DESCRIPTOR ExtendedAttributeIcb; + UDF_ENTITY_ID ImplementationIdentifier; + UINT64 UniqueId; + UINT32 LengthOfExtendedAttributes; + UINT32 LengthOfAllocationDescriptors; + UINT8 Data[0]; // L_EA + L_AD +} UDF_FILE_ENTRY; + +typedef struct { + UDF_DESCRIPTOR_TAG DescriptorTag; + UDF_ICB_TAG IcbTag; + UINT32 Uid; + UINT32 Gid; + UINT32 Permissions; + UINT16 FileLinkCount; + UINT8 RecordFormat; + UINT8 RecordDisplayAttributes; + UINT32 RecordLength; + UINT64 InformationLength; + UINT64 ObjectSize; + UINT64 LogicalBlocksRecorded; + UDF_TIMESTAMP AccessTime; + UDF_TIMESTAMP ModificationTime; + UDF_TIMESTAMP CreationTime; + UDF_TIMESTAMP AttributeTime; + UINT32 CheckPoint; + UINT32 Reserved; + UDF_LONG_ALLOCATION_DESCRIPTOR ExtendedAttributeIcb; + UDF_LONG_ALLOCATION_DESCRIPTOR StreamDirectoryIcb; + UDF_ENTITY_ID ImplementationIdentifier; + UINT64 UniqueId; + UINT32 LengthOfExtendedAttributes; + UINT32 LengthOfAllocationDescriptors; + UINT8 Data[0]; // L_EA + L_AD +} UDF_EXTENDED_FILE_ENTRY; + +typedef struct { + UINT8 ComponentType; + UINT8 LengthOfComponentIdentifier; + UINT16 ComponentFileVersionNumber; + UINT8 ComponentIdentifier[0]; +} UDF_PATH_COMPONENT; + +#pragma pack() + +// +// UDF filesystem driver's private data +// +typedef struct { + UDF_LOGICAL_VOLUME_DESCRIPTOR **LogicalVolDescs; + UINTN LogicalVolDescsNo; + UDF_PARTITION_DESCRIPTOR **PartitionDescs; + UINTN PartitionDescsNo; + UDF_FILE_SET_DESCRIPTOR **FileSetDescs; + UINTN FileSetDescsNo; + UINTN FileEntrySize; +} UDF_VOLUME_INFO; + +typedef struct { + VOID *FileEntry; + UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc; +} UDF_FILE_INFO; + +typedef struct { + VOID *DirectoryData; + UINT64 DirectoryLength; + UINT64 FidOffset; +} UDF_READ_DIRECTORY_INFO; + +#define PRIVATE_UDF_FILE_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'f', 'f') + +#define PRIVATE_UDF_FILE_DATA_FROM_THIS(a) \ + CR ( \ + a, \ + PRIVATE_UDF_FILE_DATA, \ + FileIo, \ + PRIVATE_UDF_FILE_DATA_SIGNATURE \ + ) + +typedef struct { + UINTN Signature; + BOOLEAN IsRootDirectory; + UDF_FILE_INFO *Root; + UDF_FILE_INFO File; + UDF_READ_DIRECTORY_INFO ReadDirInfo; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs; + EFI_FILE_PROTOCOL FileIo; + CHAR16 AbsoluteFileName[UDF_PATH_LENGTH]; + CHAR16 FileName[UDF_FILENAME_LENGTH]; + UINT64 FileSize; + UINT64 FilePosition; +} PRIVATE_UDF_FILE_DATA; + +#define PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'f', = 's') + +#define PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS(a) \ + CR ( \ + a, \ + PRIVATE_UDF_SIMPLE_FS_DATA, \ + SimpleFs, \ + PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE \ + ) + +typedef struct { + UINTN Signature; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs; + UDF_VOLUME_INFO Volume; + UDF_FILE_INFO Root; + UINTN OpenFiles; + EFI_HANDLE Handle; +} PRIVATE_UDF_SIMPLE_FS_DATA; + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUdfDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUdfComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gUdfComponentName2; + +// +// Function Prototypes +// + +/** + Open the root directory on a volume. + + @param This Protocol instance pointer. + @param Root Returns an Open file handle for the root directory + + @retval EFI_SUCCESS The device was opened. + @retval EFI_UNSUPPORTED This volume does not support the file syste= m. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of re= sources. + +**/ +EFI_STATUS +EFIAPI +UdfOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **Root + ); + +/** + Opens a new file relative to the source file's location. + + @param This The protocol instance pointer. + @param NewHandle Returns File Handle for FileName. + @param FileName Null terminated string. "\", ".", and ".." are suppor= ted. + @param OpenMode Open mode for file. + @param Attributes Only used for EFI_FILE_MODE_CREATE. + + @retval EFI_SUCCESS The device was opened. + @retval EFI_NOT_FOUND The specified file could not be found on th= e device. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_MEDIA_CHANGED The media has changed. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of re= sources. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +EFIAPI +UdfOpen ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ); + +/** + Read data from the file. + + @param This Protocol instance pointer. + @param BufferSize On input size of buffer, on output amount of data in = buffer. + @param Buffer The buffer in which data is read. + + @retval EFI_SUCCESS Data was read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contain= s required size. + +**/ +EFI_STATUS +EFIAPI +UdfRead ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +/** + Close the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The file was closed. + +**/ +EFI_STATUS +EFIAPI +UdfClose ( + IN EFI_FILE_PROTOCOL *This + ); + +/** + Close and delete the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The file was closed and deleted. + @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was = not + deleted. + +**/ +EFI_STATUS +EFIAPI +UdfDelete ( + IN EFI_FILE_PROTOCOL *This + ); + +/** + Write data to a file. + + @param This Protocol instance pointer. + @param BufferSize On input size of buffer, on output amount of data in = buffer. + @param Buffer The buffer in which data to write. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to Open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted f= ile. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +EFIAPI +UdfWrite ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +/** + Get file's current position. + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Position was updated. + @retval EFI_UNSUPPORTED Seek request for directories is not valid. + +**/ +EFI_STATUS +EFIAPI +UdfGetPosition ( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ); + +/** + Set file's current position. + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Position was updated. + @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. + +**/ +EFI_STATUS +EFIAPI +UdfSetPosition ( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ); + +/** + Get information about a file. + + @param This Protocol instance pointer. + @param InformationType Type of information to return in Buffer. + @param BufferSize On input size of buffer, on output amount of dat= a in buffer. + @param Buffer The buffer to return data. + + @retval EFI_SUCCESS Data was returned. + @retval EFI_UNSUPPORTED InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returne= d in BufferSize. + +**/ +EFI_STATUS +EFIAPI +UdfGetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +/** + Set information about a file. + + @param File Protocol instance pointer. + @param InformationType Type of information in Buffer. + @param BufferSize Size of buffer. + @param Buffer The data to write. + + @retval EFI_SUCCESS Data was set. + @retval EFI_UNSUPPORTED InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + +**/ +EFI_STATUS +EFIAPI +UdfSetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flush data back for the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS Data was flushed. + @retval EFI_UNSUPPORTED Writes to Open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +EFIAPI +UdfFlush ( + IN EFI_FILE_PROTOCOL *This + ); + +/** + Read volume information on a medium which contains a valid UDF file syst= em. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[out] Volume UDF volume information structure. + + @retval EFI_SUCCESS Volume information read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of reso= urces. + +**/ +EFI_STATUS +ReadUdfVolumeInformation ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + OUT UDF_VOLUME_INFO *Volume + ); + +/** + Find the root directory on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[out] File Root directory file. + + @retval EFI_SUCCESS Root directory found. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lac= k of + resources. + +**/ +EFI_STATUS +FindRootDirectory ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + OUT UDF_FILE_INFO *File + ); + +/** + Find either a File Entry or a Extended File Entry from a given ICB. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] Icb ICB of the FID. + @param[out] FileEntry File Entry or Extended File Entry. + + @retval EFI_SUCCESS File Entry or Extended File Entry found. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack = of + resources. + +**/ +EFI_STATUS +FindFileEntry ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb, + OUT VOID **FileEntry + ); + +/** + Find a file given its absolute path on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] FilePath File's absolute path. + @param[in] Root Root directory file. + @param[in] Parent Parent directory file. + @param[out] File Found file. + + @retval EFI_SUCCESS @p FilePath was found. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The @p FilePath file was not found due to l= ack of + resources. + +**/ +EFI_STATUS +FindFile ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN CHAR16 *FilePath, + IN UDF_FILE_INFO *Root, + IN UDF_FILE_INFO *Parent, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb, + OUT UDF_FILE_INFO *File + ); + +/** + Read a directory entry at a time on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] ParentIcb ICB of the parent file. + @param[in] FileEntryData FE/EFE of the parent file. + @param[in out] ReadDirInfo Next read directory listing structure + information. + @param[out] FoundFid File Identifier Descriptor pointer. + + @retval EFI_SUCCESS Directory entry read. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors not support= ed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lac= k of + resources. + +**/ +EFI_STATUS +ReadDirectoryEntry ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb, + IN VOID *FileEntryData, + IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo, + OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid + ); + +/** + Get a filename (encoded in OSTA-compressed format) from a File Identifier + Descriptor on an UDF volume. + + @param[in] FileIdentifierDesc File Identifier Descriptor pointer. + @param[out] FileName Decoded filename. + + @retval EFI_SUCCESS Filename decoded and read. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. +**/ +EFI_STATUS +GetFileNameFromFid ( + IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc, + OUT CHAR16 *FileName + ); + +/** + Resolve a symlink file on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] Parent Parent file. + @param[in] FileEntryData FE/EFE structure pointer. + @param[out] File Resolved file. + + @retval EFI_SUCCESS Symlink file resolved. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors not support= ed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to la= ck of + resources. + +**/ +EFI_STATUS +ResolveSymlink ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_FILE_INFO *Parent, + IN VOID *FileEntryData, + OUT UDF_FILE_INFO *File + ); + +/** + Clean up in-memory UDF volume information. + + @param[in] Volume Volume information pointer. + +**/ +VOID +CleanupVolumeInformation ( + IN UDF_VOLUME_INFO *Volume + ); + +/** + Clean up in-memory UDF file information. + + @param[in] File File information pointer. + +**/ +VOID +CleanupFileInformation ( + IN UDF_FILE_INFO *File + ); + +/** + Find a file from its absolute path on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] File File information structure. + @param[out] Size Size of the file. + + @retval EFI_SUCCESS File size calculated and set in @p Size. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors not support= ed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lac= k of + resources. + +**/ +EFI_STATUS +GetFileSize ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_FILE_INFO *File, + OUT UINT64 *Size + ); + +/** + Set information about a file on an UDF volume. + + @param[in] File File pointer. + @param[in] FileSize Size of the file. + @param[in] FileName Filename of the file. + @param[in out] BufferSize Size of the returned file infomation. + @param[out] Buffer Data of the returned file information. + + @retval EFI_SUCCESS File information set. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The file information was not set due to lac= k of + resources. + +**/ +EFI_STATUS +SetFileInfo ( + IN UDF_FILE_INFO *File, + IN UINT64 FileSize, + IN CHAR16 *FileName, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +/** + Get volume and free space size information of an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[out] VolumeSize Volume size. + @param[out] FreeSpaceSize Free space size. + + @retval EFI_SUCCESS Volume and free space size calculated. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The volume and free space size were not + calculated due to lack of resources. + +**/ +EFI_STATUS +GetVolumeSize ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + OUT UINT64 *VolumeSize, + OUT UINT64 *FreeSpaceSize + ); + +/** + Seek a file and read its data into memory on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] File File information structure. + @param[in] FileSize Size of the file. + @param[in out] FilePosition File position. + @param[in out] Buffer File data. + @param[in out] BufferSize Read size. + + @retval EFI_SUCCESS File seeked and read. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors not support= ed. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due t= o lack + of resources. + +**/ +EFI_STATUS +ReadFileData ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_FILE_INFO *File, + IN UINT64 FileSize, + IN OUT UINT64 *FilePosition, + IN OUT VOID *Buffer, + IN OUT UINT64 *BufferSize + ); + +/** + Check if ControllerHandle supports an UDF file system. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to test. + + @retval EFI_SUCCESS UDF file system found. + @retval EFI_UNSUPPORTED UDF file system not found. + +**/ +EFI_STATUS +SupportUdfFileSystem ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle + ); + +/** + Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..= ". + + @param[in] FileName Filename. + + @retval @p FileName Filename mangled. + +**/ +CHAR16 * +MangleFileName ( + IN CHAR16 *FileName + ); + +/** + Test to see if this driver supports ControllerHandle. Any ControllerHand= le + than contains a BlockIo and DiskIo protocol can be supported. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to test + @param RemainingDevicePath Optional parameter use to pick a specific ch= ild + device to start. + + @retval EFI_SUCCESS This driver supports this device + @retval EFI_ALREADY_STARTED This driver is already running on this device + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +UdfDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Start this driver on ControllerHandle by opening a Block IO and Disk IO + protocol, reading Device Path, and creating a child handle with a + Disk IO and device path protocol. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to bind driver to + @param RemainingDevicePath Optional parameter use to pick a specific c= hild + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHandle + @retval EFI_ALREADY_STARTED This driver is already running on Controlle= rHandle + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +UdfDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stop this driver on ControllerHandle. Support stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to stop driver on + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If num= ber of + children is zero stop the entire bus driver. + @param ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval other This driver was not removed from this device + +**/ +EFI_STATUS +EFIAPI +UdfDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form o= f a + Unicode string. If the driver specified by This has a user readable name= in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver speci= fied + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the calle= r is + requesting, and it must match one of the + languages specified in SupportedLanguages.= The + number of languages supported by a driver = is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code for= mat. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specifie= d by + This and the language specified by Languag= e was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UdfComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +/** + Retrieves a Unicode string that is the user readable name of the control= ler + that is being managed by a driver. + + This function retrieves the user readable name of the controller specifi= ed by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specif= ied by + Language, then a pointer to the controller name is returned in Controlle= rName, + and EFI_SUCCESS is returned. If the driver specified by This is not cur= rently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does = not + support the language specified by Language, then EFI_UNSUPPORTED is retu= rned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to = be + returned. + + @param ChildHandle[in] The handle of the child controller to retr= ieve + the name of. This is an optional paramete= r that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus d= rivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of= a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the calle= r is + requesting, and it must match one of the + languages specified in SupportedLanguages.= The + number of languages supported by a driver = is up + to the driver writer. Language is specifie= d in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle a= nd + ChildHandle in the language specified by + Language from the point of view of the dri= ver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable n= ame in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a va= lid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not curren= tly + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UdfComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +#endif // _UDF_H_ diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf b/MdeModulePkg/U= niversal/Disk/UdfDxe/UdfDxe.inf new file mode 100644 index 0000000000..7fea6bd9dc --- /dev/null +++ b/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf @@ -0,0 +1,66 @@ +## @file +# UDF/ECMA-167 file system driver. +# +# Copyright (C) 2014-2017 Paulo Alcantara +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD License +# which accompanies this distribution. The full text of the license may = be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D UdfDxe + FILE_GUID =3D 905f13b0-8f91-4b0a-bd76-e1e78f9422e4 + MODULE_TYPE =3D UEFI_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D InitializeUdf + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 IPF EBC +# +# DRIVER_BINDING =3D gUdfDriverBinding +# COMPONENT_NAME =3D gUdfComponentName +# COMPONENT_NAME2 =3D gUdfComponentName2 +# + +[Sources] + ComponentName.c + FileSystemOperations.c + FileName.c + File.c + Udf.c + Udf.h + + +[Packages] + MdePkg/MdePkg.dec + + +[LibraryClasses] + DevicePathLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + UefiLib + BaseLib + UefiDriverEntryPoint + DebugLib + + +[Guids] + gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## P= rotocol + gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## P= rotocol + + +[Protocols] + gEfiSimpleFileSystemProtocolGuid ## BY_START + gEfiDevicePathProtocolGuid ## BY_START + gEfiBlockIoProtocolGuid ## TO_START + gEfiDiskIoProtocolGuid ## TO_START --=20 2.11.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel