]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: Initial UDF/ECMA-167 file system support
authorPaulo Alcantara <pcacjr@zytor.com>
Fri, 8 Sep 2017 12:41:47 +0000 (09:41 -0300)
committerLaszlo Ersek <lersek@redhat.com>
Fri, 8 Sep 2017 18:42:49 +0000 (20:42 +0200)
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 <star.zeng@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Disk/UdfDxe/File.c [new file with mode: 0644]
MdeModulePkg/Universal/Disk/UdfDxe/FileName.c [new file with mode: 0644]
MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c [new file with mode: 0644]
MdeModulePkg/Universal/Disk/UdfDxe/Udf.c [new file with mode: 0644]
MdeModulePkg/Universal/Disk/UdfDxe/Udf.h [new file with mode: 0644]
MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf [new file with mode: 0644]

diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c b/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..c58bc94
--- /dev/null
@@ -0,0 +1,185 @@
+/** @file\r
+  UEFI Component Name protocol for UDF/ECMA-167 file system driver.\r
+\r
+  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include "Udf.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gUdfComponentName = {\r
+  UdfComponentNameGetDriverName,\r
+  UdfComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUdfComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UdfComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UdfComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+//\r
+// Driver name table for Udf module.\r
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUdfDriverNameTable[] = {\r
+  {\r
+    "eng;en",\r
+    L"UDF File System Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfComponentNameGetDriverName (\r
+  IN   EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN   CHAR8                        *Language,\r
+  OUT  CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+    Language,\r
+    This->SupportedLanguages,\r
+    mUdfDriverNameTable,\r
+    DriverName,\r
+    (BOOLEAN)(This == &gUdfComponentName)\r
+    );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfComponentNameGetControllerName (\r
+  IN   EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN   EFI_HANDLE                   ControllerHandle,\r
+  IN   EFI_HANDLE                   ChildHandle OPTIONAL,\r
+  IN   CHAR8                        *Language,\r
+  OUT  CHAR16                       **ControllerName\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/File.c b/MdeModulePkg/Universal/Disk/UdfDxe/File.c
new file mode 100644 (file)
index 0000000..8b93395
--- /dev/null
@@ -0,0 +1,908 @@
+/** @file\r
+  Handle operations in files and directories from UDF/ECMA-167 file systems.\r
+\r
+  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include "Udf.h"\r
+\r
+EFI_FILE_PROTOCOL gUdfFileIoOps = {\r
+  EFI_FILE_PROTOCOL_REVISION,\r
+  UdfOpen,\r
+  UdfClose,\r
+  UdfDelete,\r
+  UdfRead,\r
+  UdfWrite,\r
+  UdfGetPosition,\r
+  UdfSetPosition,\r
+  UdfGetInfo,\r
+  UdfSetInfo,\r
+  UdfFlush,\r
+  NULL,\r
+  NULL,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+#define _ROOT_FILE(_PrivData) (_PrivData)->Root\r
+#define _PARENT_FILE(_PrivData) \\r
+  ((_PrivData)->IsRootDirectory ? (_PrivData)->Root : &(_PrivData)->File)\r
+#define _FILE(_PrivData) _PARENT_FILE(_PrivData)\r
+\r
+/**\r
+  Open the root directory on a volume.\r
+\r
+  @param  This Protocol instance pointer.\r
+  @param  Root Returns an Open file handle for the root directory\r
+\r
+  @retval EFI_SUCCESS          The device was opened.\r
+  @retval EFI_UNSUPPORTED      This volume does not support the file system.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.\r
+  @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfOpenVolume (\r
+  IN   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,\r
+  OUT  EFI_FILE_PROTOCOL                **Root\r
+  )\r
+{\r
+  EFI_TPL                     OldTpl;\r
+  EFI_STATUS                  Status;\r
+  PRIVATE_UDF_SIMPLE_FS_DATA  *PrivFsData;\r
+  PRIVATE_UDF_FILE_DATA       *PrivFileData;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  if (This == NULL || Root == NULL) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Error_Invalid_Params;\r
+  }\r
+\r
+  PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This);\r
+\r
+  if (PrivFsData->OpenFiles == 0) {\r
+    //\r
+    // There is no more open files. Read volume information again since it was\r
+    // cleaned up on the last UdfClose() call.\r
+    //\r
+    Status = ReadUdfVolumeInformation (\r
+      PrivFsData->BlockIo,\r
+      PrivFsData->DiskIo,\r
+      &PrivFsData->Volume\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error_Read_Udf_Volume;\r
+    }\r
+  }\r
+\r
+  CleanupFileInformation (&PrivFsData->Root);\r
+\r
+  //\r
+  // Find root directory file.\r
+  //\r
+  Status = FindRootDirectory (\r
+    PrivFsData->BlockIo,\r
+    PrivFsData->DiskIo,\r
+    &PrivFsData->Volume,\r
+    &PrivFsData->Root\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error_Find_Root_Dir;\r
+  }\r
+\r
+  PrivFileData =\r
+    (PRIVATE_UDF_FILE_DATA *) AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));\r
+  if (PrivFileData == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error_Alloc_Priv_File_Data;\r
+  }\r
+\r
+  PrivFileData->Signature        = PRIVATE_UDF_FILE_DATA_SIGNATURE;\r
+  PrivFileData->SimpleFs         = This;\r
+  PrivFileData->Root             = &PrivFsData->Root;\r
+  PrivFileData->IsRootDirectory  = TRUE;\r
+\r
+  CopyMem ((VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps,\r
+           sizeof (EFI_FILE_PROTOCOL));\r
+\r
+  *Root = &PrivFileData->FileIo;\r
+\r
+  PrivFsData->OpenFiles++;\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Error_Alloc_Priv_File_Data:\r
+  CleanupFileInformation (&PrivFsData->Root);\r
+\r
+Error_Find_Root_Dir:\r
+  CleanupVolumeInformation (&PrivFsData->Volume);\r
+\r
+Error_Read_Udf_Volume:\r
+Error_Invalid_Params:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Opens a new file relative to the source file's location.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  NewHandle  Returns File Handle for FileName.\r
+  @param  FileName   Null terminated string. "\", ".", and ".." are supported.\r
+  @param  OpenMode   Open mode for file.\r
+  @param  Attributes Only used for EFI_FILE_MODE_CREATE.\r
+\r
+  @retval EFI_SUCCESS          The device was opened.\r
+  @retval EFI_NOT_FOUND        The specified file could not be found on the\r
+                               device.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_MEDIA_CHANGED    The media has changed.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.\r
+  @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of\r
+                               resources.\r
+  @retval EFI_VOLUME_FULL      The volume is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfOpen (\r
+  IN   EFI_FILE_PROTOCOL  *This,\r
+  OUT  EFI_FILE_PROTOCOL  **NewHandle,\r
+  IN   CHAR16             *FileName,\r
+  IN   UINT64             OpenMode,\r
+  IN   UINT64             Attributes\r
+  )\r
+{\r
+  EFI_TPL                     OldTpl;\r
+  EFI_STATUS                  Status;\r
+  PRIVATE_UDF_FILE_DATA       *PrivFileData;\r
+  PRIVATE_UDF_SIMPLE_FS_DATA  *PrivFsData;\r
+  CHAR16                      FilePath[UDF_PATH_LENGTH] = { 0 };\r
+  UDF_FILE_INFO               File;\r
+  PRIVATE_UDF_FILE_DATA       *NewPrivFileData;\r
+  CHAR16                      *TempFileName;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  if (This == NULL || NewHandle == NULL || FileName == NULL) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Error_Invalid_Params;\r
+  }\r
+\r
+  if (OpenMode != EFI_FILE_MODE_READ) {\r
+    Status = EFI_WRITE_PROTECTED;\r
+    goto Error_Invalid_Params;\r
+  }\r
+\r
+  PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
+\r
+  PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);\r
+\r
+  //\r
+  // Build full path\r
+  //\r
+  if (*FileName == L'\\') {\r
+    StrCpyS (FilePath, UDF_PATH_LENGTH, FileName);\r
+  } else {\r
+    StrCpyS (FilePath, UDF_PATH_LENGTH, PrivFileData->AbsoluteFileName);\r
+    StrCatS (FilePath, UDF_PATH_LENGTH, L"\\");\r
+    StrCatS (FilePath, UDF_PATH_LENGTH, FileName);\r
+  }\r
+\r
+  MangleFileName (FilePath);\r
+  if (FilePath[0] == L'\0') {\r
+    Status = EFI_NOT_FOUND;\r
+    goto Error_Bad_FileName;\r
+  }\r
+\r
+  Status = FindFile (\r
+    PrivFsData->BlockIo,\r
+    PrivFsData->DiskIo,\r
+    &PrivFsData->Volume,\r
+    FilePath,\r
+    _ROOT_FILE (PrivFileData),\r
+    _PARENT_FILE (PrivFileData),\r
+    &_PARENT_FILE(PrivFileData)->FileIdentifierDesc->Icb,\r
+    &File\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error_Find_File;\r
+  }\r
+\r
+  NewPrivFileData =\r
+    (PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));\r
+  if (NewPrivFileData == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error_Alloc_New_Priv_File_Data;\r
+  }\r
+\r
+  CopyMem ((VOID *)NewPrivFileData, (VOID *)PrivFileData,\r
+           sizeof (PRIVATE_UDF_FILE_DATA));\r
+  CopyMem ((VOID *)&NewPrivFileData->File, &File, sizeof (UDF_FILE_INFO));\r
+\r
+  NewPrivFileData->IsRootDirectory = FALSE;\r
+\r
+  StrCpyS (NewPrivFileData->AbsoluteFileName, UDF_PATH_LENGTH, FilePath);\r
+  FileName = NewPrivFileData->AbsoluteFileName;\r
+\r
+  while ((TempFileName = StrStr (FileName, L"\\")) != NULL) {\r
+    FileName = TempFileName + 1;\r
+  }\r
+\r
+  StrCpyS (NewPrivFileData->FileName, UDF_PATH_LENGTH, FileName);\r
+\r
+  Status = GetFileSize (\r
+    PrivFsData->BlockIo,\r
+    PrivFsData->DiskIo,\r
+    &PrivFsData->Volume,\r
+    &NewPrivFileData->File,\r
+    &NewPrivFileData->FileSize\r
+    );\r
+  ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error_Get_File_Size;\r
+  }\r
+\r
+  NewPrivFileData->FilePosition = 0;\r
+  ZeroMem ((VOID *)&NewPrivFileData->ReadDirInfo,\r
+           sizeof (UDF_READ_DIRECTORY_INFO));\r
+\r
+  *NewHandle = &NewPrivFileData->FileIo;\r
+\r
+  PrivFsData->OpenFiles++;\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+\r
+Error_Get_File_Size:\r
+  FreePool ((VOID *)NewPrivFileData);\r
+\r
+Error_Alloc_New_Priv_File_Data:\r
+  CleanupFileInformation (&File);\r
+\r
+Error_Find_File:\r
+Error_Bad_FileName:\r
+Error_Invalid_Params:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read data from the file.\r
+\r
+  @param  This       Protocol instance pointer.\r
+  @param  BufferSize On input size of buffer, on output amount of data in\r
+                     buffer.\r
+  @param  Buffer     The buffer in which data is read.\r
+\r
+  @retval EFI_SUCCESS          Data was read.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_BUFFER_TO_SMALL  BufferSize is too small. BufferSize contains\r
+                               required size.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfRead (\r
+  IN      EFI_FILE_PROTOCOL  *This,\r
+  IN OUT  UINTN              *BufferSize,\r
+  OUT     VOID               *Buffer\r
+  )\r
+{\r
+  EFI_TPL                         OldTpl;\r
+  EFI_STATUS                      Status;\r
+  PRIVATE_UDF_FILE_DATA           *PrivFileData;\r
+  PRIVATE_UDF_SIMPLE_FS_DATA      *PrivFsData;\r
+  UDF_VOLUME_INFO                 *Volume;\r
+  UDF_FILE_INFO                   *Parent;\r
+  UDF_READ_DIRECTORY_INFO         *ReadDirInfo;\r
+  EFI_BLOCK_IO_PROTOCOL           *BlockIo;\r
+  EFI_DISK_IO_PROTOCOL            *DiskIo;\r
+  UDF_FILE_INFO                   FoundFile;\r
+  UDF_FILE_IDENTIFIER_DESCRIPTOR  *NewFileIdentifierDesc;\r
+  VOID                            *NewFileEntryData;\r
+  CHAR16                          FileName[UDF_FILENAME_LENGTH] = { 0 };\r
+  UINT64                          FileSize;\r
+  UINT64                          BufferSizeUint64;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  if (This == NULL || BufferSize == NULL || (*BufferSize != 0 &&\r
+                                             Buffer == NULL)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Error_Invalid_Params;\r
+  }\r
+\r
+  PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
+  PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);\r
+\r
+  BlockIo                = PrivFsData->BlockIo;\r
+  DiskIo                 = PrivFsData->DiskIo;\r
+  Volume                 = &PrivFsData->Volume;\r
+  ReadDirInfo            = &PrivFileData->ReadDirInfo;\r
+  NewFileIdentifierDesc  = NULL;\r
+  NewFileEntryData       = NULL;\r
+\r
+  Parent = _PARENT_FILE (PrivFileData);\r
+\r
+  Status = EFI_VOLUME_CORRUPTED;\r
+\r
+  if (IS_FID_NORMAL_FILE (Parent->FileIdentifierDesc)) {\r
+    if (PrivFileData->FilePosition > PrivFileData->FileSize) {\r
+      //\r
+      // File's position is beyond the EOF\r
+      //\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Error_File_Beyond_The_Eof;\r
+    }\r
+\r
+    if (PrivFileData->FilePosition == PrivFileData->FileSize) {\r
+      *BufferSize = 0;\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+\r
+    BufferSizeUint64 = *BufferSize;\r
+\r
+    Status = ReadFileData (\r
+      BlockIo,\r
+      DiskIo,\r
+      Volume,\r
+      Parent,\r
+      PrivFileData->FileSize,\r
+      &PrivFileData->FilePosition,\r
+      Buffer,\r
+      &BufferSizeUint64\r
+      );\r
+    ASSERT (BufferSizeUint64 <= MAX_UINTN);\r
+    *BufferSize = (UINTN)BufferSizeUint64;\r
+  } else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) {\r
+    if (ReadDirInfo->FidOffset == 0 && PrivFileData->FilePosition > 0) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      *BufferSize = 0;\r
+      goto Done;\r
+    }\r
+\r
+    for (;;) {\r
+      Status = ReadDirectoryEntry (\r
+        BlockIo,\r
+        DiskIo,\r
+        Volume,\r
+        &Parent->FileIdentifierDesc->Icb,\r
+        Parent->FileEntry,\r
+        ReadDirInfo,\r
+        &NewFileIdentifierDesc\r
+        );\r
+      if (EFI_ERROR (Status)) {\r
+        if (Status == EFI_DEVICE_ERROR) {\r
+          FreePool (ReadDirInfo->DirectoryData);\r
+          ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));\r
+\r
+          *BufferSize = 0;\r
+          Status = EFI_SUCCESS;\r
+        }\r
+\r
+        goto Done;\r
+      }\r
+\r
+      if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) {\r
+        break;\r
+      }\r
+\r
+      FreePool ((VOID *)NewFileIdentifierDesc);\r
+    }\r
+\r
+    Status = FindFileEntry (\r
+      BlockIo,\r
+      DiskIo,\r
+      Volume,\r
+      &NewFileIdentifierDesc->Icb,\r
+      &NewFileEntryData\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error_Find_Fe;\r
+    }\r
+\r
+    if (IS_FE_SYMLINK (NewFileEntryData)) {\r
+      Status = ResolveSymlink (\r
+        BlockIo,\r
+        DiskIo,\r
+        Volume,\r
+        Parent,\r
+        NewFileEntryData,\r
+        &FoundFile\r
+        );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error_Resolve_Symlink;\r
+      }\r
+\r
+      FreePool ((VOID *)NewFileEntryData);\r
+      NewFileEntryData = FoundFile.FileEntry;\r
+\r
+      Status = GetFileNameFromFid (NewFileIdentifierDesc, FileName);\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool ((VOID *)FoundFile.FileIdentifierDesc);\r
+        goto Error_Get_FileName;\r
+      }\r
+\r
+      FreePool ((VOID *)NewFileIdentifierDesc);\r
+      NewFileIdentifierDesc = FoundFile.FileIdentifierDesc;\r
+    } else {\r
+      FoundFile.FileIdentifierDesc  = NewFileIdentifierDesc;\r
+      FoundFile.FileEntry           = NewFileEntryData;\r
+\r
+      Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, FileName);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error_Get_FileName;\r
+      }\r
+    }\r
+\r
+    Status = GetFileSize (\r
+      BlockIo,\r
+      DiskIo,\r
+      Volume,\r
+      &FoundFile,\r
+      &FileSize\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error_Get_File_Size;\r
+    }\r
+\r
+    Status = SetFileInfo (\r
+      &FoundFile,\r
+      FileSize,\r
+      FileName,\r
+      BufferSize,\r
+      Buffer\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error_Set_File_Info;\r
+    }\r
+\r
+    PrivFileData->FilePosition++;\r
+    Status = EFI_SUCCESS;\r
+  } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Error_Set_File_Info:\r
+Error_Get_File_Size:\r
+Error_Get_FileName:\r
+Error_Resolve_Symlink:\r
+  if (NewFileEntryData != NULL) {\r
+    FreePool (NewFileEntryData);\r
+  }\r
+\r
+Error_Find_Fe:\r
+  if (NewFileIdentifierDesc != NULL) {\r
+    FreePool ((VOID *)NewFileIdentifierDesc);\r
+  }\r
+\r
+Done:\r
+Error_File_Beyond_The_Eof:\r
+Error_Invalid_Params:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Close the file handle.\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS The file was closed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfClose (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  )\r
+{\r
+  EFI_TPL                     OldTpl;\r
+  EFI_STATUS                  Status;\r
+  PRIVATE_UDF_FILE_DATA       *PrivFileData;\r
+  PRIVATE_UDF_SIMPLE_FS_DATA  *PrivFsData;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (This == NULL) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Exit;\r
+  }\r
+\r
+  PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
+\r
+  PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);\r
+\r
+  if (!PrivFileData->IsRootDirectory) {\r
+    CleanupFileInformation (&PrivFileData->File);\r
+\r
+    if (PrivFileData->ReadDirInfo.DirectoryData != NULL) {\r
+      FreePool (PrivFileData->ReadDirInfo.DirectoryData);\r
+    }\r
+  }\r
+\r
+  if (--PrivFsData->OpenFiles == 0) {\r
+    CleanupVolumeInformation (&PrivFsData->Volume);\r
+  }\r
+\r
+  FreePool ((VOID *)PrivFileData);\r
+\r
+Exit:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Close and delete the file handle.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS              The file was closed and deleted.\r
+  @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not\r
+                                   deleted.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfDelete (\r
+  IN EFI_FILE_PROTOCOL  *This\r
+  )\r
+{\r
+  PRIVATE_UDF_FILE_DATA *PrivFileData;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
+\r
+  (VOID)PrivFileData->FileIo.Close(This);\r
+\r
+  return EFI_WARN_DELETE_FAILURE;\r
+}\r
+\r
+/**\r
+  Write data to a file.\r
+\r
+  @param  This       Protocol instance pointer.\r
+  @param  BufferSize On input size of buffer, on output amount of data in\r
+                     buffer.\r
+  @param  Buffer     The buffer in which data to write.\r
+\r
+  @retval EFI_SUCCESS          Data was written.\r
+  @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED  The device is write protected.\r
+  @retval EFI_ACCESS_DENIED    The file was open for read only.\r
+  @retval EFI_VOLUME_FULL      The volume is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfWrite (\r
+  IN      EFI_FILE_PROTOCOL  *This,\r
+  IN OUT  UINTN              *BufferSize,\r
+  IN      VOID               *Buffer\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Get file's current position.\r
+\r
+  @param  This      Protocol instance pointer.\r
+  @param  Position  Byte position from the start of the file.\r
+\r
+  @retval EFI_SUCCESS      Position was updated.\r
+  @retval EFI_UNSUPPORTED  Seek request for directories is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfGetPosition (\r
+  IN   EFI_FILE_PROTOCOL  *This,\r
+  OUT  UINT64             *Position\r
+  )\r
+{\r
+  PRIVATE_UDF_FILE_DATA *PrivFileData;\r
+\r
+  if (This == NULL || Position == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // As per UEFI spec, if the file handle is a directory, then the current file\r
+  // position has no meaning and the operation is not supported.\r
+  //\r
+  if (IS_FID_DIRECTORY_FILE (&PrivFileData->File.FileIdentifierDesc)) {\r
+    return  EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // The file is not a directory. So, return its position.\r
+  //\r
+  *Position = PrivFileData->FilePosition;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set file's current position.\r
+\r
+  @param  This      Protocol instance pointer.\r
+  @param  Position  Byte position from the start of the file.\r
+\r
+  @retval EFI_SUCCESS      Position was updated.\r
+  @retval EFI_UNSUPPORTED  Seek request for non-zero is not valid on open.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfSetPosition (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN UINT64             Position\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  PRIVATE_UDF_FILE_DATA           *PrivFileData;\r
+  UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
+\r
+  FileIdentifierDesc = PrivFileData->File.FileIdentifierDesc;\r
+  if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) {\r
+    //\r
+    // If the file handle is a directory, the _only_ position that may be set is\r
+    // zero. This has no effect of starting the read proccess of the directory\r
+    // entries over.\r
+    //\r
+    if (Position == 0) {\r
+      PrivFileData->FilePosition = Position;\r
+      PrivFileData->ReadDirInfo.FidOffset = 0;\r
+      Status = EFI_SUCCESS;\r
+    }\r
+  } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) {\r
+    //\r
+    // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be\r
+    // set to the EOF.\r
+    //\r
+    if (Position == 0xFFFFFFFFFFFFFFFF) {\r
+      PrivFileData->FilePosition = PrivFileData->FileSize - 1;\r
+    } else {\r
+      PrivFileData->FilePosition = Position;\r
+    }\r
+\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get information about a file.\r
+\r
+  @param  This            Protocol instance pointer.\r
+  @param  InformationType Type of information to return in Buffer.\r
+  @param  BufferSize      On input size of buffer, on output amount of data in\r
+                          buffer.\r
+  @param  Buffer          The buffer to return data.\r
+\r
+  @retval EFI_SUCCESS          Data was returned.\r
+  @retval EFI_UNSUPPORTED      InformationType is not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED  The device is write protected.\r
+  @retval EFI_ACCESS_DENIED    The file was open for read only.\r
+  @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in\r
+                               BufferSize.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfGetInfo (\r
+  IN      EFI_FILE_PROTOCOL  *This,\r
+  IN      EFI_GUID           *InformationType,\r
+  IN OUT  UINTN              *BufferSize,\r
+  OUT     VOID               *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  PRIVATE_UDF_FILE_DATA       *PrivFileData;\r
+  PRIVATE_UDF_SIMPLE_FS_DATA  *PrivFsData;\r
+  EFI_FILE_SYSTEM_INFO        *FileSystemInfo;\r
+  UINTN                       FileSystemInfoLength;\r
+  CHAR16                      *String;\r
+  UDF_FILE_SET_DESCRIPTOR     *FileSetDesc;\r
+  UINTN                       Index;\r
+  UINT8                       *OstaCompressed;\r
+  UINT8                       CompressionId;\r
+  UINT64                      VolumeSize;\r
+  UINT64                      FreeSpaceSize;\r
+  CHAR16                      VolumeLabel[64];\r
+\r
+  if (This == NULL || InformationType == NULL || BufferSize == NULL ||\r
+      (*BufferSize != 0 && Buffer == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
+\r
+  PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
+    Status = SetFileInfo (\r
+      _FILE (PrivFileData),\r
+      PrivFileData->FileSize,\r
+      PrivFileData->FileName,\r
+      BufferSize,\r
+      Buffer\r
+      );\r
+  } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
+    String = VolumeLabel;\r
+\r
+    FileSetDesc = PrivFsData->Volume.FileSetDescs[0];\r
+\r
+    OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];\r
+\r
+    CompressionId = OstaCompressed[0];\r
+    if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
+      return EFI_VOLUME_CORRUPTED;\r
+    }\r
+\r
+    for (Index = 1; Index < 128; Index++) {\r
+      if (CompressionId == 16) {\r
+        *String = *(UINT8 *)(OstaCompressed + Index) << 8;\r
+        Index++;\r
+      } else {\r
+        *String = 0;\r
+      }\r
+\r
+      if (Index < 128) {\r
+        *String |= *(UINT8 *)(OstaCompressed + Index);\r
+      }\r
+\r
+      //\r
+      // Unlike FID Identifiers, Logical Volume Identifier is stored in a\r
+      // NULL-terminated OSTA compressed format, so we must check for the NULL\r
+      // character.\r
+      //\r
+      if (*String == L'\0') {\r
+        break;\r
+      }\r
+\r
+      String++;\r
+    }\r
+\r
+    *String = L'\0';\r
+\r
+    FileSystemInfoLength = StrSize (VolumeLabel) +\r
+                           sizeof (EFI_FILE_SYSTEM_INFO);\r
+    if (*BufferSize < FileSystemInfoLength) {\r
+      *BufferSize = FileSystemInfoLength;\r
+      return EFI_BUFFER_TOO_SMALL;\r
+    }\r
+\r
+    FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;\r
+    StrCpyS (FileSystemInfo->VolumeLabel, ARRAY_SIZE (VolumeLabel),\r
+             VolumeLabel);\r
+    Status = GetVolumeSize (\r
+      PrivFsData->BlockIo,\r
+      PrivFsData->DiskIo,\r
+      &PrivFsData->Volume,\r
+      &VolumeSize,\r
+      &FreeSpaceSize\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    FileSystemInfo->Size        = FileSystemInfoLength;\r
+    FileSystemInfo->ReadOnly    = TRUE;\r
+    FileSystemInfo->BlockSize   =\r
+      LV_BLOCK_SIZE (&PrivFsData->Volume, UDF_DEFAULT_LV_NUM);\r
+    FileSystemInfo->VolumeSize  = VolumeSize;\r
+    FileSystemInfo->FreeSpace   = FreeSpaceSize;\r
+\r
+    *BufferSize = FileSystemInfoLength;\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set information about a file.\r
+\r
+  @param  File            Protocol instance pointer.\r
+  @param  InformationType Type of information in Buffer.\r
+  @param  BufferSize      Size of buffer.\r
+  @param  Buffer          The data to write.\r
+\r
+  @retval EFI_SUCCESS          Data was set.\r
+  @retval EFI_UNSUPPORTED      InformationType is not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED  The device is write protected.\r
+  @retval EFI_ACCESS_DENIED    The file was open for read only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfSetInfo (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN EFI_GUID           *InformationType,\r
+  IN UINTN              BufferSize,\r
+  IN VOID               *Buffer\r
+  )\r
+{\r
+  return EFI_WRITE_PROTECTED;\r
+}\r
+\r
+/**\r
+  Flush data back for the file handle.\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS          Data was flushed.\r
+  @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED  The device is write protected.\r
+  @retval EFI_ACCESS_DENIED    The file was open for read only.\r
+  @retval EFI_VOLUME_FULL      The volume is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfFlush (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  )\r
+{\r
+  return EFI_WRITE_PROTECTED;\r
+}\r
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c b/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c
new file mode 100644 (file)
index 0000000..f737933
--- /dev/null
@@ -0,0 +1,195 @@
+/** @file\r
+  Helper functions for mangling file names in UDF/ECMA-167 file systems.\r
+\r
+  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include "Udf.h"\r
+\r
+CHAR16 *\r
+TrimString (\r
+  IN CHAR16    *String\r
+  )\r
+{\r
+  CHAR16       *TempString;\r
+\r
+  for ( ; *String != L'\0' && *String == L' '; String++) {\r
+    ;\r
+  }\r
+\r
+  TempString = String + StrLen (String) - 1;\r
+  while ((TempString >= String) && (*TempString == L' ')) {\r
+    TempString--;\r
+  }\r
+\r
+  *(TempString + 1) = L'\0';\r
+\r
+  return String;\r
+}\r
+\r
+VOID\r
+ReplaceLeft (\r
+  IN CHAR16         *Destination,\r
+  IN CONST CHAR16   *Source\r
+  )\r
+{\r
+  CONST CHAR16      *EndString;\r
+\r
+  EndString = Source + StrLen (Source);\r
+  while (Source <= EndString) {\r
+    *Destination++ = *Source++;\r
+  }\r
+}\r
+\r
+CHAR16 *\r
+ExcludeTrailingBackslashes (\r
+  IN CHAR16                    *String\r
+  )\r
+{\r
+  CHAR16                       *TempString;\r
+\r
+  switch (*(String + 1)) {\r
+  case L'\\':\r
+    break;\r
+  case L'\0':\r
+  default:\r
+    String++;\r
+    goto Exit;\r
+  }\r
+\r
+  TempString = String;\r
+  while (*TempString != L'\0' && *TempString == L'\\') {\r
+    TempString++;\r
+  }\r
+\r
+  if (TempString - 1 > String) {\r
+    ReplaceLeft (String + 1, TempString);\r
+  }\r
+\r
+  String++;\r
+\r
+Exit:\r
+  return String;\r
+}\r
+\r
+/**\r
+  Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..".\r
+\r
+  @param[in] FileName Filename.\r
+\r
+  @retval @p FileName Filename mangled.\r
+\r
+**/\r
+CHAR16 *\r
+MangleFileName (\r
+  IN CHAR16        *FileName\r
+  )\r
+{\r
+  CHAR16           *FileNameSavedPointer;\r
+  CHAR16           *TempFileName;\r
+  UINTN            BackslashesNo;\r
+\r
+  if (FileName == NULL || *FileName == L'\0') {\r
+    FileName = NULL;\r
+    goto Exit;\r
+  }\r
+\r
+  FileName = TrimString (FileName);\r
+  if (*FileName == L'\0') {\r
+    goto Exit;\r
+  }\r
+\r
+  if ((StrLen (FileName) > 1) && (FileName[StrLen (FileName) - 1] == L'\\')) {\r
+    FileName[StrLen (FileName) - 1] = L'\0';\r
+  }\r
+\r
+  FileNameSavedPointer = FileName;\r
+\r
+  if (FileName[0] == L'.') {\r
+    if (FileName[1] == L'.') {\r
+      if (FileName[2] == L'\0') {\r
+        goto Exit;\r
+      } else {\r
+        FileName += 2;\r
+      }\r
+    } else if (FileName[1] == L'\0') {\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  while (*FileName != L'\0') {\r
+    if (*FileName == L'\\') {\r
+      FileName = ExcludeTrailingBackslashes (FileName);\r
+    } else if (*FileName == L'.') {\r
+      switch (*(FileName + 1)) {\r
+      case L'\0':\r
+        *FileName = L'\0';\r
+        break;\r
+      case L'\\':\r
+        TempFileName = FileName + 1;\r
+        TempFileName = ExcludeTrailingBackslashes (TempFileName);\r
+        ReplaceLeft (FileName, TempFileName);\r
+        break;\r
+      case '.':\r
+        if ((*(FileName - 1) != L'\\') && ((*(FileName + 2) != L'\\') ||\r
+                                           (*(FileName + 2) != L'\0'))) {\r
+          FileName++;\r
+          continue;\r
+        }\r
+\r
+        BackslashesNo = 0;\r
+        TempFileName = FileName - 1;\r
+        while (TempFileName >= FileNameSavedPointer) {\r
+          if (*TempFileName == L'\\') {\r
+            if (++BackslashesNo == 2) {\r
+              break;\r
+            }\r
+          }\r
+\r
+          TempFileName--;\r
+        }\r
+\r
+        TempFileName++;\r
+\r
+        if ((*TempFileName == L'.') && (*(TempFileName + 1) == L'.')) {\r
+          FileName += 2;\r
+        } else {\r
+          if (*(FileName + 2) != L'\0') {\r
+            ReplaceLeft (TempFileName, FileName + 3);\r
+            if (*(TempFileName - 1) == L'\\') {\r
+              FileName = TempFileName;\r
+              ExcludeTrailingBackslashes (TempFileName - 1);\r
+              TempFileName = FileName;\r
+            }\r
+          } else {\r
+            *TempFileName = L'\0';\r
+          }\r
+\r
+          FileName = TempFileName;\r
+        }\r
+\r
+        break;\r
+      default:\r
+        FileName++;\r
+      }\r
+    } else {\r
+      FileName++;\r
+    }\r
+  }\r
+\r
+  FileName = FileNameSavedPointer;\r
+  if ((StrLen (FileName) > 1) && (FileName [StrLen (FileName) - 1] == L'\\')) {\r
+    FileName [StrLen (FileName) - 1] = L'\0';\r
+  }\r
+\r
+Exit:\r
+  return FileName;\r
+}\r
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c b/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
new file mode 100644 (file)
index 0000000..7d7f722
--- /dev/null
@@ -0,0 +1,2447 @@
+/** @file\r
+  Handle on-disk format and volume structures in UDF/ECMA-167 file systems.\r
+\r
+  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include "Udf.h"\r
+\r
+EFI_STATUS\r
+FindAnchorVolumeDescriptorPointer (\r
+  IN   EFI_BLOCK_IO_PROTOCOL                 *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL                  *DiskIo,\r
+  OUT  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoint\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      BlockSize = BlockIo->Media->BlockSize;\r
+  EFI_LBA     EndLBA = BlockIo->Media->LastBlock;\r
+  EFI_LBA     DescriptorLBAs[] = { 256, EndLBA - 256, EndLBA, 512 };\r
+  UINTN       Index;\r
+\r
+  for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {\r
+    Status = DiskIo->ReadDisk (\r
+      DiskIo,\r
+      BlockIo->Media->MediaId,\r
+      MultU64x32 (DescriptorLBAs[Index], BlockSize),\r
+      sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),\r
+      (VOID *)AnchorPoint\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Check if read LBA has a valid AVDP descriptor.\r
+    //\r
+    if (IS_AVDP (AnchorPoint)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  //\r
+  // No AVDP found.\r
+  //\r
+  return EFI_VOLUME_CORRUPTED;\r
+}\r
+\r
+EFI_STATUS\r
+StartMainVolumeDescriptorSequence (\r
+  IN   EFI_BLOCK_IO_PROTOCOL                 *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL                  *DiskIo,\r
+  IN   UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoint,\r
+  OUT  UDF_VOLUME_INFO                       *Volume\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINT32                         BlockSize;\r
+  UDF_EXTENT_AD                  *ExtentAd;\r
+  UINT64                         StartingLsn;\r
+  UINT64                         EndingLsn;\r
+  VOID                           *Buffer;\r
+  UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc;\r
+  UDF_PARTITION_DESCRIPTOR       *PartitionDesc;\r
+  UINTN                          Index;\r
+  UINT32                         LogicalBlockSize;\r
+\r
+  //\r
+  // We've already found an ADVP on the volume. It contains the extent\r
+  // (MainVolumeDescriptorSequenceExtent) where the Main Volume Descriptor\r
+  // Sequence starts. Therefore, we'll look for Logical Volume Descriptors and\r
+  // Partitions Descriptors and save them in memory, accordingly.\r
+  //\r
+  // Note also that each descriptor will be aligned on a block size (BlockSize)\r
+  // boundary, so we need to read one block at a time.\r
+  //\r
+  BlockSize    = BlockIo->Media->BlockSize;\r
+  ExtentAd     = &AnchorPoint->MainVolumeDescriptorSequenceExtent;\r
+  StartingLsn  = (UINT64)ExtentAd->ExtentLocation;\r
+  EndingLsn    = StartingLsn + DivU64x32 (\r
+                                     (UINT64)ExtentAd->ExtentLength,\r
+                                     BlockSize\r
+                                     );\r
+\r
+  Volume->LogicalVolDescs =\r
+    (UDF_LOGICAL_VOLUME_DESCRIPTOR **)AllocateZeroPool (ExtentAd->ExtentLength);\r
+  if (Volume->LogicalVolDescs == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Volume->PartitionDescs =\r
+    (UDF_PARTITION_DESCRIPTOR **)AllocateZeroPool (ExtentAd->ExtentLength);\r
+  if (Volume->PartitionDescs == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error_Alloc_Pds;\r
+  }\r
+\r
+  Buffer = AllocateZeroPool (BlockSize);\r
+  if (Buffer == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error_Alloc_Buf;\r
+  }\r
+\r
+  Volume->LogicalVolDescsNo  = 0;\r
+  Volume->PartitionDescsNo   = 0;\r
+\r
+  while (StartingLsn <= EndingLsn) {\r
+    Status = DiskIo->ReadDisk (\r
+      DiskIo,\r
+      BlockIo->Media->MediaId,\r
+      MultU64x32 (StartingLsn, BlockSize),\r
+      BlockSize,\r
+      Buffer\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error_Read_Disk_Blk;\r
+    }\r
+\r
+    if (IS_TD (Buffer)) {\r
+      //\r
+      // Found a Terminating Descriptor. Stop the sequence then.\r
+      //\r
+      break;\r
+    }\r
+\r
+    if (IS_LVD (Buffer)) {\r
+      //\r
+      // Found a Logical Volume Descriptor.\r
+      //\r
+      LogicalVolDesc =\r
+        (UDF_LOGICAL_VOLUME_DESCRIPTOR *)\r
+        AllocateZeroPool (sizeof (UDF_LOGICAL_VOLUME_DESCRIPTOR));\r
+      if (LogicalVolDesc == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Error_Alloc_Lvd;\r
+      }\r
+\r
+      CopyMem ((VOID *)LogicalVolDesc, Buffer,\r
+               sizeof (UDF_LOGICAL_VOLUME_DESCRIPTOR));\r
+      Volume->LogicalVolDescs[Volume->LogicalVolDescsNo++] = LogicalVolDesc;\r
+    } else if (IS_PD (Buffer)) {\r
+      //\r
+      // Found a Partition Descriptor.\r
+      //\r
+      PartitionDesc =\r
+        (UDF_PARTITION_DESCRIPTOR *)\r
+        AllocateZeroPool (sizeof (UDF_PARTITION_DESCRIPTOR));\r
+      if (PartitionDesc == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Error_Alloc_Pd;\r
+      }\r
+\r
+      CopyMem ((VOID *)PartitionDesc, Buffer,\r
+               sizeof (UDF_PARTITION_DESCRIPTOR));\r
+      Volume->PartitionDescs[Volume->PartitionDescsNo++] = PartitionDesc;\r
+    }\r
+\r
+    StartingLsn++;\r
+  }\r
+\r
+  //\r
+  // When an UDF volume (revision 2.00 or higher) contains a File Entry rather\r
+  // than an Extended File Entry (which is not recommended as per spec), we need\r
+  // to make sure the size of a FE will be _at least_ 2048\r
+  // (UDF_LOGICAL_SECTOR_SIZE) bytes long to keep backward compatibility.\r
+  //\r
+  LogicalBlockSize = LV_BLOCK_SIZE (Volume, UDF_DEFAULT_LV_NUM);\r
+  if (LogicalBlockSize >= UDF_LOGICAL_SECTOR_SIZE) {\r
+    Volume->FileEntrySize = LogicalBlockSize;\r
+  } else {\r
+    Volume->FileEntrySize = UDF_LOGICAL_SECTOR_SIZE;\r
+  }\r
+\r
+  FreePool (Buffer);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Error_Alloc_Pd:\r
+Error_Alloc_Lvd:\r
+  for (Index = 0; Index < Volume->PartitionDescsNo; Index++) {\r
+    FreePool ((VOID *)Volume->PartitionDescs[Index]);\r
+  }\r
+\r
+  for (Index = 0; Index < Volume->LogicalVolDescsNo; Index++) {\r
+    FreePool ((VOID *)Volume->LogicalVolDescs[Index]);\r
+  }\r
+\r
+Error_Read_Disk_Blk:\r
+  FreePool (Buffer);\r
+\r
+Error_Alloc_Buf:\r
+  FreePool ((VOID *)Volume->PartitionDescs);\r
+  Volume->PartitionDescs = NULL;\r
+\r
+Error_Alloc_Pds:\r
+  FreePool ((VOID *)Volume->LogicalVolDescs);\r
+  Volume->LogicalVolDescs = NULL;\r
+\r
+  return Status;\r
+}\r
+\r
+//\r
+// Return a Partition Descriptor given a Long Allocation Descriptor. This is\r
+// necessary to calculate the right extent (LongAd) offset which is added up\r
+// with partition's starting location.\r
+//\r
+UDF_PARTITION_DESCRIPTOR *\r
+GetPdFromLongAd (\r
+  IN UDF_VOLUME_INFO                 *Volume,\r
+  IN UDF_LONG_ALLOCATION_DESCRIPTOR  *LongAd\r
+  )\r
+{\r
+  UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc;\r
+  UINTN                          Index;\r
+  UDF_PARTITION_DESCRIPTOR       *PartitionDesc;\r
+  UINT16                         PartitionNum;\r
+\r
+  LogicalVolDesc = Volume->LogicalVolDescs[UDF_DEFAULT_LV_NUM];\r
+\r
+  switch (LV_UDF_REVISION (LogicalVolDesc)) {\r
+  case 0x0102:\r
+    //\r
+    // As per UDF 1.02 specification:\r
+    //\r
+    // There shall be exactly one prevailing Logical Volume Descriptor recorded\r
+    // per Volume Set. The Partition Maps field shall contain only Type 1\r
+    // Partition Maps.\r
+    //\r
+    PartitionNum = *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]);\r
+    break;\r
+  case 0x0150:\r
+    //\r
+    // Ensure Type 1 Partition map. Other types aren't supported in this\r
+    // implementation.\r
+    //\r
+    if (LogicalVolDesc->PartitionMaps[0] != 1 ||\r
+        LogicalVolDesc->PartitionMaps[1] != 6) {\r
+      return NULL;\r
+    }\r
+    PartitionNum = *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]);\r
+    break;\r
+  case 0x0260:\r
+    //\r
+    // Fall through.\r
+    //\r
+  default:\r
+    PartitionNum = LongAd->ExtentLocation.PartitionReferenceNumber;\r
+    break;\r
+  }\r
+\r
+  for (Index = 0; Index < Volume->PartitionDescsNo; Index++) {\r
+    PartitionDesc = Volume->PartitionDescs[Index];\r
+    if (PartitionDesc->PartitionNumber == PartitionNum) {\r
+      return PartitionDesc;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+//\r
+// Return logical sector number of a given Long Allocation Descriptor.\r
+//\r
+UINT64\r
+GetLongAdLsn (\r
+  IN UDF_VOLUME_INFO                 *Volume,\r
+  IN UDF_LONG_ALLOCATION_DESCRIPTOR  *LongAd\r
+  )\r
+{\r
+  UDF_PARTITION_DESCRIPTOR *PartitionDesc;\r
+\r
+  PartitionDesc = GetPdFromLongAd (Volume, LongAd);\r
+  ASSERT (PartitionDesc != NULL);\r
+\r
+  return (UINT64)PartitionDesc->PartitionStartingLocation +\r
+                 LongAd->ExtentLocation.LogicalBlockNumber;\r
+}\r
+\r
+//\r
+// Return logical sector number of a given Short Allocation Descriptor.\r
+//\r
+UINT64\r
+GetShortAdLsn (\r
+  IN UDF_PARTITION_DESCRIPTOR         *PartitionDesc,\r
+  IN UDF_SHORT_ALLOCATION_DESCRIPTOR  *ShortAd\r
+  )\r
+{\r
+  return (UINT64)PartitionDesc->PartitionStartingLocation +\r
+    ShortAd->ExtentPosition;\r
+}\r
+\r
+//\r
+// Find File Set Descriptor of a given Logical Volume Descriptor.\r
+//\r
+// The found FSD will contain the extent (LogicalVolumeContentsUse) where our\r
+// root directory is.\r
+//\r
+EFI_STATUS\r
+FindFileSetDescriptor (\r
+  IN   EFI_BLOCK_IO_PROTOCOL    *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL     *DiskIo,\r
+  IN   UDF_VOLUME_INFO          *Volume,\r
+  IN   UINTN                    LogicalVolDescNum,\r
+  OUT  UDF_FILE_SET_DESCRIPTOR  *FileSetDesc\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINT64                         Lsn;\r
+  UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc;\r
+\r
+  LogicalVolDesc = Volume->LogicalVolDescs[LogicalVolDescNum];\r
+  Lsn = GetLongAdLsn (Volume, &LogicalVolDesc->LogicalVolumeContentsUse);\r
+\r
+  //\r
+  // Read extent (Long Ad).\r
+  //\r
+  Status = DiskIo->ReadDisk (\r
+    DiskIo,\r
+    BlockIo->Media->MediaId,\r
+    MultU64x32 (Lsn, LogicalVolDesc->LogicalBlockSize),\r
+    sizeof (UDF_FILE_SET_DESCRIPTOR),\r
+    (VOID *)FileSetDesc\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check if the read extent contains a valid FSD's tag identifier.\r
+  //\r
+  if (!IS_FSD (FileSetDesc)) {\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// Get all File Set Descriptors for each Logical Volume Descriptor.\r
+//\r
+EFI_STATUS\r
+GetFileSetDescriptors (\r
+  IN      EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN      EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN OUT  UDF_VOLUME_INFO        *Volume\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  UINTN                    Index;\r
+  UDF_FILE_SET_DESCRIPTOR  *FileSetDesc;\r
+  UINTN                    Count;\r
+\r
+  Volume->FileSetDescs =\r
+    (UDF_FILE_SET_DESCRIPTOR **)AllocateZeroPool (\r
+      Volume->LogicalVolDescsNo * sizeof (UDF_FILE_SET_DESCRIPTOR));\r
+  if (Volume->FileSetDescs == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (Index = 0; Index < Volume->LogicalVolDescsNo; Index++) {\r
+    FileSetDesc = AllocateZeroPool (sizeof (UDF_FILE_SET_DESCRIPTOR));\r
+    if (FileSetDesc == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Error_Alloc_Fsd;\r
+    }\r
+\r
+    //\r
+    // Find a FSD for this LVD.\r
+    //\r
+    Status = FindFileSetDescriptor (\r
+      BlockIo,\r
+      DiskIo,\r
+      Volume,\r
+      Index,\r
+      FileSetDesc\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error_Find_Fsd;\r
+    }\r
+\r
+    //\r
+    // Got one. Save it.\r
+    //\r
+    Volume->FileSetDescs[Index] = FileSetDesc;\r
+  }\r
+\r
+  Volume->FileSetDescsNo = Volume->LogicalVolDescsNo;\r
+  return EFI_SUCCESS;\r
+\r
+Error_Find_Fsd:\r
+  Count = Index + 1;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    FreePool ((VOID *)Volume->FileSetDescs[Index]);\r
+  }\r
+\r
+  FreePool ((VOID *)Volume->FileSetDescs);\r
+  Volume->FileSetDescs = NULL;\r
+\r
+Error_Alloc_Fsd:\r
+  return Status;\r
+}\r
+\r
+//\r
+// Read Volume and File Structure on an UDF file system.\r
+//\r
+EFI_STATUS\r
+ReadVolumeFileStructure (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  OUT  UDF_VOLUME_INFO        *Volume\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  AnchorPoint;\r
+\r
+  //\r
+  // Find an AVDP.\r
+  //\r
+  Status = FindAnchorVolumeDescriptorPointer (\r
+    BlockIo,\r
+    DiskIo,\r
+    &AnchorPoint\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // AVDP has been found. Start MVDS.\r
+  //\r
+  Status = StartMainVolumeDescriptorSequence (\r
+    BlockIo,\r
+    DiskIo,\r
+    &AnchorPoint,\r
+    Volume\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+//\r
+// Calculate length of a given File Identifier Descriptor.\r
+//\r
+UINT64\r
+GetFidDescriptorLength (\r
+  IN UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc\r
+  )\r
+{\r
+  return (UINT64)(\r
+             (INTN)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR, Data[0]) + 3 +\r
+             FileIdentifierDesc->LengthOfFileIdentifier +\r
+             FileIdentifierDesc->LengthOfImplementationUse) >> 2) << 2\r
+             );\r
+}\r
+\r
+//\r
+// Duplicate a given File Identifier Descriptor.\r
+//\r
+VOID\r
+DuplicateFid (\r
+  IN   UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc,\r
+  OUT  UDF_FILE_IDENTIFIER_DESCRIPTOR  **NewFileIdentifierDesc\r
+  )\r
+{\r
+  *NewFileIdentifierDesc =\r
+    (UDF_FILE_IDENTIFIER_DESCRIPTOR *)AllocateCopyPool (\r
+      GetFidDescriptorLength (FileIdentifierDesc), FileIdentifierDesc);\r
+}\r
+\r
+//\r
+// Duplicate either a given File Entry or a given Extended File Entry.\r
+//\r
+VOID\r
+DuplicateFe (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   UDF_VOLUME_INFO        *Volume,\r
+  IN   VOID                   *FileEntry,\r
+  OUT  VOID                   **NewFileEntry\r
+  )\r
+{\r
+  *NewFileEntry = AllocateCopyPool (Volume->FileEntrySize, FileEntry);\r
+}\r
+\r
+//\r
+// Get raw data + length of a given File Entry or Extended File Entry.\r
+//\r
+// The file's recorded data can contain either real file content (inline) or\r
+// a sequence of extents (or Allocation Descriptors) which tells where file's\r
+// content is stored in.\r
+//\r
+// NOTE: The FE/EFE can be thought it was an inode.\r
+//\r
+VOID\r
+GetFileEntryData (\r
+  IN   VOID    *FileEntryData,\r
+  OUT  VOID    **Data,\r
+  OUT  UINT64  *Length\r
+  )\r
+{\r
+  UDF_EXTENDED_FILE_ENTRY  *ExtendedFileEntry;\r
+  UDF_FILE_ENTRY           *FileEntry;\r
+\r
+  if (IS_EFE (FileEntryData)) {\r
+    ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;\r
+\r
+    *Length  = ExtendedFileEntry->InformationLength;\r
+    *Data    = (VOID *)((UINT8 *)ExtendedFileEntry->Data +\r
+                        ExtendedFileEntry->LengthOfExtendedAttributes);\r
+  } else if (IS_FE (FileEntryData)) {\r
+    FileEntry = (UDF_FILE_ENTRY *)FileEntryData;\r
+\r
+    *Length  = FileEntry->InformationLength;\r
+    *Data    = (VOID *)((UINT8 *)FileEntry->Data +\r
+                        FileEntry->LengthOfExtendedAttributes);\r
+  }\r
+}\r
+\r
+//\r
+// Get Allocation Descriptors' data information from a given FE/EFE.\r
+//\r
+VOID\r
+GetAdsInformation (\r
+  IN   VOID    *FileEntryData,\r
+  OUT  VOID    **AdsData,\r
+  OUT  UINT64  *Length\r
+  )\r
+{\r
+  UDF_EXTENDED_FILE_ENTRY  *ExtendedFileEntry;\r
+  UDF_FILE_ENTRY           *FileEntry;\r
+\r
+  if (IS_EFE (FileEntryData)) {\r
+    ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;\r
+\r
+    *Length = ExtendedFileEntry->LengthOfAllocationDescriptors;\r
+    *AdsData = (VOID *)((UINT8 *)ExtendedFileEntry->Data +\r
+                        ExtendedFileEntry->LengthOfExtendedAttributes);\r
+  } else if (IS_FE (FileEntryData)) {\r
+    FileEntry = (UDF_FILE_ENTRY *)FileEntryData;\r
+\r
+    *Length = FileEntry->LengthOfAllocationDescriptors;\r
+    *AdsData = (VOID *)((UINT8 *)FileEntry->Data +\r
+                        FileEntry->LengthOfExtendedAttributes);\r
+  }\r
+}\r
+\r
+//\r
+// Read next Long Allocation Descriptor from a given file's data.\r
+//\r
+EFI_STATUS\r
+GetLongAdFromAds (\r
+  IN      VOID                            *Data,\r
+  IN OUT  UINT64                          *Offset,\r
+  IN      UINT64                          Length,\r
+  OUT     UDF_LONG_ALLOCATION_DESCRIPTOR  **FoundLongAd\r
+  )\r
+{\r
+  UDF_LONG_ALLOCATION_DESCRIPTOR  *LongAd;\r
+  UDF_EXTENT_FLAGS                ExtentFlags;\r
+\r
+  for (;;) {\r
+    if (*Offset >= Length) {\r
+      //\r
+      // No more Long Allocation Descriptors.\r
+      //\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    LongAd =\r
+      (UDF_LONG_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);\r
+\r
+    //\r
+    // If it's either an indirect AD (Extended Alllocation Descriptor) or an\r
+    // allocated AD, then return it.\r
+    //\r
+    ExtentFlags = GET_EXTENT_FLAGS (LONG_ADS_SEQUENCE, LongAd);\r
+    if (ExtentFlags == EXTENT_IS_NEXT_EXTENT ||\r
+        ExtentFlags == EXTENT_RECORDED_AND_ALLOCATED) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // This AD is either not recorded but allocated, or not recorded and not\r
+    // allocated. Skip it.\r
+    //\r
+    *Offset += AD_LENGTH (LONG_ADS_SEQUENCE);\r
+  }\r
+\r
+  *FoundLongAd = LongAd;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// Read next Short Allocation Descriptor from a given file's data.\r
+//\r
+EFI_STATUS\r
+GetShortAdFromAds (\r
+  IN      VOID                             *Data,\r
+  IN OUT  UINT64                           *Offset,\r
+  IN      UINT64                           Length,\r
+  OUT     UDF_SHORT_ALLOCATION_DESCRIPTOR  **FoundShortAd\r
+  )\r
+{\r
+  UDF_SHORT_ALLOCATION_DESCRIPTOR *ShortAd;\r
+  UDF_EXTENT_FLAGS                ExtentFlags;\r
+\r
+  for (;;) {\r
+    if (*Offset >= Length) {\r
+      //\r
+      // No more Short Allocation Descriptors.\r
+      //\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    ShortAd =\r
+      (UDF_SHORT_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);\r
+\r
+    //\r
+    // If it's either an indirect AD (Extended Alllocation Descriptor) or an\r
+    // allocated AD, then return it.\r
+    //\r
+    ExtentFlags = GET_EXTENT_FLAGS (SHORT_ADS_SEQUENCE, ShortAd);\r
+    if (ExtentFlags == EXTENT_IS_NEXT_EXTENT ||\r
+        ExtentFlags == EXTENT_RECORDED_AND_ALLOCATED) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // This AD is either not recorded but allocated, or not recorded and not\r
+    // allocated. Skip it.\r
+    //\r
+    *Offset += AD_LENGTH (SHORT_ADS_SEQUENCE);\r
+  }\r
+\r
+  *FoundShortAd = ShortAd;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// Get either a Short Allocation Descriptor or a Long Allocation Descriptor from\r
+// file's data.\r
+//\r
+EFI_STATUS\r
+GetAllocationDescriptor (\r
+  IN      UDF_FE_RECORDING_FLAGS  RecordingFlags,\r
+  IN      VOID                    *Data,\r
+  IN OUT  UINT64                  *Offset,\r
+  IN      UINT64                  Length,\r
+  OUT     VOID                    **FoundAd\r
+  )\r
+{\r
+  if (RecordingFlags == LONG_ADS_SEQUENCE) {\r
+    return GetLongAdFromAds (\r
+      Data,\r
+      Offset,\r
+      Length,\r
+      (UDF_LONG_ALLOCATION_DESCRIPTOR **)FoundAd\r
+      );\r
+  } else if (RecordingFlags == SHORT_ADS_SEQUENCE) {\r
+    return GetShortAdFromAds (\r
+      Data,\r
+      Offset,\r
+      Length,\r
+      (UDF_SHORT_ALLOCATION_DESCRIPTOR **)FoundAd\r
+      );\r
+  }\r
+\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+//\r
+// Return logical sector number of either Short or Long Allocation Descriptor.\r
+//\r
+UINT64\r
+GetAllocationDescriptorLsn (\r
+  IN UDF_FE_RECORDING_FLAGS          RecordingFlags,\r
+  IN UDF_VOLUME_INFO                 *Volume,\r
+  IN UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,\r
+  IN VOID                            *Ad\r
+  )\r
+{\r
+  if (RecordingFlags == LONG_ADS_SEQUENCE) {\r
+    return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad);\r
+  } else if (RecordingFlags == SHORT_ADS_SEQUENCE) {\r
+    return GetShortAdLsn (\r
+      GetPdFromLongAd (Volume, ParentIcb),\r
+      (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad\r
+      );\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+//\r
+// Return offset + length of a given indirect Allocation Descriptor (AED).\r
+//\r
+EFI_STATUS\r
+GetAedAdsOffset (\r
+  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN   UDF_VOLUME_INFO                 *Volume,\r
+  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,\r
+  IN   UDF_FE_RECORDING_FLAGS          RecordingFlags,\r
+  IN   VOID                            *Ad,\r
+  OUT  UINT64                          *Offset,\r
+  OUT  UINT64                          *Length\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT32                            ExtentLength;\r
+  UINT64                            Lsn;\r
+  VOID                              *Data;\r
+  UINT32                            LogicalBlockSize;\r
+  UDF_ALLOCATION_EXTENT_DESCRIPTOR  *AllocExtDesc;\r
+\r
+  ExtentLength  = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
+  Lsn           = GetAllocationDescriptorLsn (RecordingFlags,\r
+                                              Volume,\r
+                                              ParentIcb,\r
+                                              Ad);\r
+\r
+  Data = AllocatePool (ExtentLength);\r
+  if (Data == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  LogicalBlockSize = LV_BLOCK_SIZE (Volume, UDF_DEFAULT_LV_NUM);\r
+\r
+  //\r
+  // Read extent.\r
+  //\r
+  Status = DiskIo->ReadDisk (\r
+    DiskIo,\r
+    BlockIo->Media->MediaId,\r
+    MultU64x32 (Lsn, LogicalBlockSize),\r
+    ExtentLength,\r
+    Data\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Check if read extent contains a valid tag identifier for AED.\r
+  //\r
+  AllocExtDesc = (UDF_ALLOCATION_EXTENT_DESCRIPTOR *)Data;\r
+  if (!IS_AED (AllocExtDesc)) {\r
+    Status = EFI_VOLUME_CORRUPTED;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Get AED's block offset and its length.\r
+  //\r
+  *Offset = MultU64x32 (Lsn, LogicalBlockSize) +\r
+    sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR);\r
+  *Length = AllocExtDesc->LengthOfAllocationDescriptors;\r
+\r
+Exit:\r
+  FreePool (Data);\r
+\r
+  return Status;\r
+}\r
+\r
+//\r
+// Read Allocation Extent Descriptor into memory.\r
+//\r
+EFI_STATUS\r
+GetAedAdsData (\r
+  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN   UDF_VOLUME_INFO                 *Volume,\r
+  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,\r
+  IN   UDF_FE_RECORDING_FLAGS          RecordingFlags,\r
+  IN   VOID                            *Ad,\r
+  OUT  VOID                            **Data,\r
+  OUT  UINT64                          *Length\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT64      Offset;\r
+\r
+  //\r
+  // Get AED's offset + length.\r
+  //\r
+  Status = GetAedAdsOffset (\r
+    BlockIo,\r
+    DiskIo,\r
+    Volume,\r
+    ParentIcb,\r
+    RecordingFlags,\r
+    Ad,\r
+    &Offset,\r
+    Length\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer to read in AED's data.\r
+  //\r
+  *Data = AllocatePool (*Length);\r
+  if (*Data == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  return DiskIo->ReadDisk (\r
+    DiskIo,\r
+    BlockIo->Media->MediaId,\r
+    Offset,\r
+    *Length,\r
+    *Data\r
+    );\r
+}\r
+\r
+//\r
+// Function used to serialise reads of Allocation Descriptors.\r
+//\r
+EFI_STATUS\r
+GrowUpBufferToNextAd (\r
+  IN      UDF_FE_RECORDING_FLAGS  RecordingFlags,\r
+  IN      VOID                    *Ad,\r
+  IN OUT  VOID                    **Buffer,\r
+  IN      UINT64                  Length\r
+  )\r
+{\r
+  UINT32 ExtentLength;\r
+\r
+  ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
+\r
+  if (*Buffer == NULL) {\r
+    *Buffer = AllocatePool (ExtentLength);\r
+    if (*Buffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  } else {\r
+    *Buffer = ReallocatePool (Length, Length + ExtentLength, *Buffer);\r
+    if (*Buffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// Read data or size of either a File Entry or an Extended File Entry.\r
+//\r
+EFI_STATUS\r
+ReadFile (\r
+  IN      EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN      EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN      UDF_VOLUME_INFO                 *Volume,\r
+  IN      UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,\r
+  IN      VOID                            *FileEntryData,\r
+  IN OUT  UDF_READ_FILE_INFO              *ReadFileInfo\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT32                  LogicalBlockSize;\r
+  VOID                    *Data;\r
+  UINT64                  Length;\r
+  VOID                    *Ad;\r
+  UINT64                  AdOffset;\r
+  UINT64                  Lsn;\r
+  BOOLEAN                 DoFreeAed;\r
+  UINT64                  FilePosition;\r
+  UINT64                  Offset;\r
+  UINT64                  DataOffset;\r
+  UINT64                  BytesLeft;\r
+  UINT64                  DataLength;\r
+  BOOLEAN                 FinishedSeeking;\r
+  UINT32                  ExtentLength;\r
+  UDF_FE_RECORDING_FLAGS  RecordingFlags;\r
+\r
+  LogicalBlockSize  = LV_BLOCK_SIZE (Volume, UDF_DEFAULT_LV_NUM);\r
+  DoFreeAed         = FALSE;\r
+\r
+  switch (ReadFileInfo->Flags) {\r
+  case READ_FILE_GET_FILESIZE:\r
+  case READ_FILE_ALLOCATE_AND_READ:\r
+    //\r
+    // Initialise ReadFileInfo structure for either getting file size, or\r
+    // reading file's recorded data.\r
+    //\r
+    ReadFileInfo->ReadLength = 0;\r
+    ReadFileInfo->FileData = NULL;\r
+    break;\r
+  case READ_FILE_SEEK_AND_READ:\r
+    //\r
+    // About to seek a file and/or read its data.\r
+    //\r
+    Length = ReadFileInfo->FileSize - ReadFileInfo->FilePosition;\r
+    if (ReadFileInfo->FileDataSize > Length) {\r
+      //\r
+      // About to read beyond the EOF -- truncate it.\r
+      //\r
+      ReadFileInfo->FileDataSize = Length;\r
+    }\r
+\r
+    //\r
+    // Initialise data to start seeking and/or reading a file.\r
+    //\r
+    BytesLeft = ReadFileInfo->FileDataSize;\r
+    DataOffset = 0;\r
+    FilePosition = 0;\r
+    FinishedSeeking = FALSE;\r
+\r
+    break;\r
+  }\r
+\r
+  RecordingFlags = GET_FE_RECORDING_FLAGS (FileEntryData);\r
+  switch (RecordingFlags) {\r
+  case INLINE_DATA:\r
+    //\r
+    // There are no extents for this FE/EFE. All data is inline.\r
+    //\r
+    GetFileEntryData (FileEntryData, &Data, &Length);\r
+\r
+    if (ReadFileInfo->Flags == READ_FILE_GET_FILESIZE) {\r
+      ReadFileInfo->ReadLength = Length;\r
+    } else if (ReadFileInfo->Flags == READ_FILE_ALLOCATE_AND_READ) {\r
+      //\r
+      // Allocate buffer for starting read data.\r
+      //\r
+      ReadFileInfo->FileData = AllocatePool (Length);\r
+      if (ReadFileInfo->FileData == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      //\r
+      // Read all inline data into ReadFileInfo->FileData\r
+      //\r
+      CopyMem (ReadFileInfo->FileData, Data, Length);\r
+      ReadFileInfo->ReadLength = Length;\r
+    } else if (ReadFileInfo->Flags == READ_FILE_SEEK_AND_READ) {\r
+      //\r
+      // If FilePosition is non-zero, seek file to FilePosition, read\r
+      // FileDataSize bytes and then updates FilePosition.\r
+      //\r
+      CopyMem (\r
+        ReadFileInfo->FileData,\r
+        (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition),\r
+        ReadFileInfo->FileDataSize\r
+        );\r
+\r
+      ReadFileInfo->FilePosition += ReadFileInfo->FileDataSize;\r
+    }\r
+\r
+    break;\r
+  case LONG_ADS_SEQUENCE:\r
+  case SHORT_ADS_SEQUENCE:\r
+    //\r
+    // This FE/EFE contains a run of Allocation Descriptors. Get data + size\r
+    // for start reading them out.\r
+    //\r
+    GetAdsInformation (FileEntryData, &Data, &Length);\r
+    AdOffset = 0;\r
+\r
+    for (;;) {\r
+      //\r
+      // Read AD.\r
+      //\r
+      Status = GetAllocationDescriptor (\r
+        RecordingFlags,\r
+        Data,\r
+        &AdOffset,\r
+        Length,\r
+        &Ad\r
+        );\r
+      if (Status == EFI_DEVICE_ERROR) {\r
+        Status = EFI_SUCCESS;\r
+        goto Done;\r
+      }\r
+\r
+      //\r
+      // Check if AD is an indirect AD. If so, read Allocation Extent\r
+      // Descriptor and its extents (ADs).\r
+      //\r
+      if (GET_EXTENT_FLAGS (RecordingFlags, Ad) == EXTENT_IS_NEXT_EXTENT) {\r
+        if (!DoFreeAed) {\r
+          DoFreeAed = TRUE;\r
+        } else {\r
+          FreePool (Data);\r
+        }\r
+\r
+        Status = GetAedAdsData (\r
+          BlockIo,\r
+          DiskIo,\r
+          Volume,\r
+          ParentIcb,\r
+          RecordingFlags,\r
+          Ad,\r
+          &Data,\r
+          &Length\r
+          );\r
+        if (EFI_ERROR (Status)) {\r
+          goto Error_Get_Aed;\r
+        }\r
+\r
+        AdOffset = 0;\r
+        continue;\r
+      }\r
+\r
+      ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
+\r
+      Lsn = GetAllocationDescriptorLsn (RecordingFlags,\r
+                                        Volume,\r
+                                        ParentIcb,\r
+                                        Ad);\r
+\r
+      switch (ReadFileInfo->Flags) {\r
+      case READ_FILE_GET_FILESIZE:\r
+        ReadFileInfo->ReadLength += ExtentLength;\r
+        break;\r
+      case READ_FILE_ALLOCATE_AND_READ:\r
+        //\r
+        // Increase FileData (if necessary) to read next extent.\r
+        //\r
+        Status = GrowUpBufferToNextAd (\r
+          RecordingFlags,\r
+          Ad,\r
+          &ReadFileInfo->FileData,\r
+          ReadFileInfo->ReadLength\r
+          );\r
+        if (EFI_ERROR (Status)) {\r
+          goto Error_Alloc_Buffer_To_Next_Ad;\r
+        }\r
+\r
+        //\r
+        // Read extent's data into FileData.\r
+        //\r
+        Status = DiskIo->ReadDisk (\r
+          DiskIo,\r
+          BlockIo->Media->MediaId,\r
+          MultU64x32 (Lsn, LogicalBlockSize),\r
+          ExtentLength,\r
+          (VOID *)((UINT8 *)ReadFileInfo->FileData +\r
+                   ReadFileInfo->ReadLength)\r
+          );\r
+        if (EFI_ERROR (Status)) {\r
+          goto Error_Read_Disk_Blk;\r
+        }\r
+\r
+        ReadFileInfo->ReadLength += ExtentLength;\r
+        break;\r
+      case READ_FILE_SEEK_AND_READ:\r
+        //\r
+        // Seek file first before reading in its data.\r
+        //\r
+        if (FinishedSeeking) {\r
+          Offset = 0;\r
+          goto Skip_File_Seek;\r
+        }\r
+\r
+        if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) {\r
+          FilePosition += ExtentLength;\r
+          goto Skip_Ad;\r
+        }\r
+\r
+        if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) {\r
+          Offset = ReadFileInfo->FilePosition - FilePosition;\r
+          if (Offset < 0) {\r
+            Offset = -(Offset);\r
+          }\r
+        } else {\r
+          Offset = 0;\r
+        }\r
+\r
+        //\r
+        // Done with seeking file. Start reading its data.\r
+        //\r
+        FinishedSeeking = TRUE;\r
+\r
+      Skip_File_Seek:\r
+        //\r
+        // Make sure we don't read more data than really wanted.\r
+        //\r
+        if (ExtentLength - Offset > BytesLeft) {\r
+          DataLength = BytesLeft;\r
+        } else {\r
+          DataLength = ExtentLength - Offset;\r
+        }\r
+\r
+        //\r
+        // Read extent's data into FileData.\r
+        //\r
+        Status = DiskIo->ReadDisk (\r
+          DiskIo,\r
+          BlockIo->Media->MediaId,\r
+          Offset + MultU64x32 (Lsn, LogicalBlockSize),\r
+          DataLength,\r
+          (VOID *)((UINT8 *)ReadFileInfo->FileData +\r
+                   DataOffset)\r
+          );\r
+        if (EFI_ERROR (Status)) {\r
+          goto Error_Read_Disk_Blk;\r
+        }\r
+\r
+        //\r
+        // Update current file's position.\r
+        //\r
+        DataOffset += DataLength;\r
+        ReadFileInfo->FilePosition += DataLength;\r
+\r
+        BytesLeft -= DataLength;\r
+        if (BytesLeft == 0) {\r
+          //\r
+          // There is no more file data to read.\r
+          //\r
+          Status = EFI_SUCCESS;\r
+          goto Done;\r
+        }\r
+\r
+        break;\r
+      }\r
+\r
+    Skip_Ad:\r
+      //\r
+      // Point to the next AD (extent).\r
+      //\r
+      AdOffset += AD_LENGTH (RecordingFlags);\r
+    }\r
+\r
+    break;\r
+  case EXTENDED_ADS_SEQUENCE:\r
+     // FIXME: Not supported. Got no volume with it, yet.\r
+    ASSERT (FALSE);\r
+    Status = EFI_UNSUPPORTED;\r
+    break;\r
+  }\r
+\r
+Done:\r
+  if (DoFreeAed) {\r
+    FreePool (Data);\r
+  }\r
+\r
+  return Status;\r
+\r
+Error_Read_Disk_Blk:\r
+Error_Alloc_Buffer_To_Next_Ad:\r
+  if (ReadFileInfo->Flags != READ_FILE_SEEK_AND_READ) {\r
+    FreePool (ReadFileInfo->FileData);\r
+  }\r
+\r
+  if (DoFreeAed) {\r
+    FreePool (Data);\r
+  }\r
+\r
+Error_Get_Aed:\r
+  return Status;\r
+}\r
+\r
+//\r
+// Find a file by its filename from a given Parent file.\r
+//\r
+EFI_STATUS\r
+InternalFindFile (\r
+  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN   UDF_VOLUME_INFO                 *Volume,\r
+  IN   CHAR16                          *FileName,\r
+  IN   UDF_FILE_INFO                   *Parent,\r
+  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *Icb,\r
+  OUT  UDF_FILE_INFO                   *File\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc;\r
+  UDF_READ_DIRECTORY_INFO         ReadDirInfo;\r
+  BOOLEAN                         Found;\r
+  CHAR16                          FoundFileName[UDF_FILENAME_LENGTH];\r
+  VOID                            *CompareFileEntry;\r
+\r
+  //\r
+  // Check if parent file is really directory.\r
+  //\r
+  if (!IS_FE_DIRECTORY (Parent->FileEntry)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // If FileName is current file or working directory, just duplicate Parent's\r
+  // FE/EFE and FID descriptors.\r
+  //\r
+  if (StrCmp (FileName, L".") == 0) {\r
+    DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);\r
+    DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Start directory listing.\r
+  //\r
+  ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));\r
+  Found = FALSE;\r
+\r
+  for (;;) {\r
+    Status = ReadDirectoryEntry (\r
+      BlockIo,\r
+      DiskIo,\r
+      Volume,\r
+      Parent->FileIdentifierDesc ?\r
+      &Parent->FileIdentifierDesc->Icb :\r
+      Icb,\r
+      Parent->FileEntry,\r
+      &ReadDirInfo,\r
+      &FileIdentifierDesc\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      if (Status == EFI_DEVICE_ERROR) {\r
+        Status = EFI_NOT_FOUND;\r
+      }\r
+\r
+      break;\r
+    }\r
+\r
+    if (IS_FID_PARENT_FILE (FileIdentifierDesc)) {\r
+      //\r
+      // This FID contains the location (FE/EFE) of the parent directory of this\r
+      // directory (Parent), and if FileName is either ".." or "\\", then it's\r
+      // the expected FID.\r
+      //\r
+      if (StrCmp (FileName, L"..") == 0 || StrCmp (FileName, L"\\") == 0) {\r
+        Found = TRUE;\r
+        break;\r
+      }\r
+    } else {\r
+      Status = GetFileNameFromFid (FileIdentifierDesc, FoundFileName);\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+\r
+      if (StrCmp (FileName, FoundFileName) == 0) {\r
+        //\r
+        // FID has been found. Prepare to find its respective FE/EFE.\r
+        //\r
+        Found = TRUE;\r
+        break;\r
+      }\r
+    }\r
+\r
+    FreePool ((VOID *)FileIdentifierDesc);\r
+  }\r
+\r
+  if (ReadDirInfo.DirectoryData != NULL) {\r
+    //\r
+    // Free all allocated resources for the directory listing.\r
+    //\r
+    FreePool (ReadDirInfo.DirectoryData);\r
+  }\r
+\r
+  if (Found) {\r
+    Status = EFI_SUCCESS;\r
+\r
+    File->FileIdentifierDesc = FileIdentifierDesc;\r
+\r
+    //\r
+    // If the requested file is root directory, then the FE/EFE was already\r
+    // retrieved in UdfOpenVolume() function, thus no need to find it again.\r
+    //\r
+    // Otherwise, find FE/EFE from the respective FID.\r
+    //\r
+    if (StrCmp (FileName, L"\\") != 0) {\r
+      Status = FindFileEntry (\r
+        BlockIo,\r
+        DiskIo,\r
+        Volume,\r
+        &FileIdentifierDesc->Icb,\r
+        &CompareFileEntry\r
+        );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error_Find_Fe;\r
+      }\r
+\r
+      //\r
+      // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.\r
+      //\r
+      if (CompareMem ((VOID *)Parent->FileEntry, (VOID *)CompareFileEntry,\r
+                      Volume->FileEntrySize) != 0) {\r
+        File->FileEntry = CompareFileEntry;\r
+      } else {\r
+        FreePool ((VOID *)FileIdentifierDesc);\r
+        FreePool ((VOID *)CompareFileEntry);\r
+        Status = EFI_NOT_FOUND;\r
+      }\r
+    }\r
+  }\r
+\r
+  return Status;\r
+\r
+Error_Find_Fe:\r
+  FreePool ((VOID *)FileIdentifierDesc);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read volume information on a medium which contains a valid UDF file system.\r
+\r
+  @param[in]   BlockIo  BlockIo interface.\r
+  @param[in]   DiskIo   DiskIo interface.\r
+  @param[out]  Volume   UDF volume information structure.\r
+\r
+  @retval EFI_SUCCESS          Volume information read.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadUdfVolumeInformation (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  OUT  UDF_VOLUME_INFO        *Volume\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  Status = ReadVolumeFileStructure (\r
+    BlockIo,\r
+    DiskIo,\r
+    Volume\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = GetFileSetDescriptors (\r
+    BlockIo,\r
+    DiskIo,\r
+    Volume\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    CleanupVolumeInformation (Volume);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Find the root directory on an UDF volume.\r
+\r
+  @param[in]   BlockIo  BlockIo interface.\r
+  @param[in]   DiskIo   DiskIo interface.\r
+  @param[in]   Volume   UDF volume information structure.\r
+  @param[out]  File     Root directory file.\r
+\r
+  @retval EFI_SUCCESS          Root directory found.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+FindRootDirectory (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN   UDF_VOLUME_INFO        *Volume,\r
+  OUT  UDF_FILE_INFO          *File\r
+  )\r
+{\r
+  EFI_STATUS     Status;\r
+  UDF_FILE_INFO  Parent;\r
+\r
+  Status = FindFileEntry (\r
+    BlockIo,\r
+    DiskIo,\r
+    Volume,\r
+    &Volume->FileSetDescs[0]->RootDirectoryIcb,\r
+    &File->FileEntry\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Parent.FileEntry = File->FileEntry;\r
+  Parent.FileIdentifierDesc = NULL;\r
+\r
+  Status = FindFile (\r
+    BlockIo,\r
+    DiskIo,\r
+    Volume,\r
+    L"\\",\r
+    NULL,\r
+    &Parent,\r
+    &Volume->FileSetDescs[0]->RootDirectoryIcb,\r
+    File\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (File->FileEntry);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Find either a File Entry or a Extended File Entry from a given ICB.\r
+\r
+  @param[in]   BlockIo    BlockIo interface.\r
+  @param[in]   DiskIo     DiskIo interface.\r
+  @param[in]   Volume     UDF volume information structure.\r
+  @param[in]   Icb        ICB of the FID.\r
+  @param[out]  FileEntry  File Entry or Extended File Entry.\r
+\r
+  @retval EFI_SUCCESS          File Entry or Extended File Entry found.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+FindFileEntry (\r
+  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN   UDF_VOLUME_INFO                 *Volume,\r
+  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *Icb,\r
+  OUT  VOID                            **FileEntry\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT64      Lsn;\r
+  UINT32      LogicalBlockSize;\r
+\r
+  Lsn               = GetLongAdLsn (Volume, Icb);\r
+  LogicalBlockSize  = LV_BLOCK_SIZE (Volume, UDF_DEFAULT_LV_NUM);\r
+\r
+  *FileEntry = AllocateZeroPool (Volume->FileEntrySize);\r
+  if (*FileEntry == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Read extent.\r
+  //\r
+  Status = DiskIo->ReadDisk (\r
+    DiskIo,\r
+    BlockIo->Media->MediaId,\r
+    MultU64x32 (Lsn, LogicalBlockSize),\r
+    Volume->FileEntrySize,\r
+    *FileEntry\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error_Read_Disk_Blk;\r
+  }\r
+\r
+  //\r
+  // Check if the read extent contains a valid Tag Identifier for the expected\r
+  // FE/EFE.\r
+  //\r
+  if (!IS_FE (*FileEntry) && !IS_EFE (*FileEntry)) {\r
+    Status = EFI_VOLUME_CORRUPTED;\r
+    goto Error_Invalid_Fe;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Error_Invalid_Fe:\r
+Error_Read_Disk_Blk:\r
+  FreePool (*FileEntry);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Find a file given its absolute path on an UDF volume.\r
+\r
+  @param[in]   BlockIo   BlockIo interface.\r
+  @param[in]   DiskIo    DiskIo interface.\r
+  @param[in]   Volume    UDF volume information structure.\r
+  @param[in]   FilePath  File's absolute path.\r
+  @param[in]   Root      Root directory file.\r
+  @param[in]   Parent    Parent directory file.\r
+  @param[out]  File      Found file.\r
+\r
+  @retval EFI_SUCCESS          @p FilePath was found.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The @p FilePath file was not found due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+FindFile (\r
+  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN   UDF_VOLUME_INFO                 *Volume,\r
+  IN   CHAR16                          *FilePath,\r
+  IN   UDF_FILE_INFO                   *Root,\r
+  IN   UDF_FILE_INFO                   *Parent,\r
+  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *Icb,\r
+  OUT  UDF_FILE_INFO                   *File\r
+  )\r
+{\r
+  EFI_STATUS     Status;\r
+  CHAR16         FileName[UDF_FILENAME_LENGTH];\r
+  CHAR16         *FileNamePointer;\r
+  UDF_FILE_INFO  PreviousFile;\r
+  VOID           *FileEntry;\r
+\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));\r
+  while (*FilePath != L'\0') {\r
+    FileNamePointer = FileName;\r
+    while (*FilePath != L'\0' && *FilePath != L'\\') {\r
+      *FileNamePointer++ = *FilePath++;\r
+    }\r
+\r
+    *FileNamePointer = L'\0';\r
+    if (FileName[0] == L'\0') {\r
+      //\r
+      // Open root directory.\r
+      //\r
+      if (Root == NULL) {\r
+        //\r
+        // There is no file found for the root directory yet. So, find only its\r
+        // FID by now.\r
+        //\r
+        // See UdfOpenVolume() function.\r
+        //\r
+        Status = InternalFindFile (BlockIo,\r
+                                   DiskIo,\r
+                                   Volume,\r
+                                   L"\\",\r
+                                   &PreviousFile,\r
+                                   Icb,\r
+                                   File);\r
+      } else {\r
+        //\r
+        // We've already a file pointer (Root) for the root directory. Duplicate\r
+        // its FE/EFE and FID descriptors.\r
+        //\r
+        DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);\r
+        DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);\r
+        Status = EFI_SUCCESS;\r
+      }\r
+    } else {\r
+      //\r
+      // No root directory. Find filename from the current directory.\r
+      //\r
+      Status = InternalFindFile (BlockIo,\r
+                                 DiskIo,\r
+                                 Volume,\r
+                                 FileName,\r
+                                 &PreviousFile,\r
+                                 Icb,\r
+                                 File);\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // If the found file is a symlink, then find its respective FE/EFE and\r
+    // FID descriptors.\r
+    //\r
+    if (IS_FE_SYMLINK (File->FileEntry)) {\r
+      FreePool ((VOID *)File->FileIdentifierDesc);\r
+\r
+      FileEntry = File->FileEntry;\r
+\r
+      Status = ResolveSymlink (BlockIo,\r
+                               DiskIo,\r
+                               Volume,\r
+                               &PreviousFile,\r
+                               FileEntry,\r
+                               File);\r
+\r
+      FreePool (FileEntry);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
+                    sizeof (UDF_FILE_INFO)) != 0) {\r
+      CleanupFileInformation (&PreviousFile);\r
+    }\r
+\r
+    CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));\r
+    if (*FilePath != L'\0' && *FilePath == L'\\') {\r
+      FilePath++;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read a directory entry at a time on an UDF volume.\r
+\r
+  @param[in]      BlockIo        BlockIo interface.\r
+  @param[in]      DiskIo         DiskIo interface.\r
+  @param[in]      Volume         UDF volume information structure.\r
+  @param[in]      ParentIcb      ICB of the parent file.\r
+  @param[in]      FileEntryData  FE/EFE of the parent file.\r
+  @param[in out]  ReadDirInfo    Next read directory listing structure\r
+                                 information.\r
+  @param[out]     FoundFid       File Identifier Descriptor pointer.\r
+\r
+  @retval EFI_SUCCESS          Directory entry read.\r
+  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadDirectoryEntry (\r
+  IN      EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN      EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN      UDF_VOLUME_INFO                 *Volume,\r
+  IN      UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,\r
+  IN      VOID                            *FileEntryData,\r
+  IN OUT  UDF_READ_DIRECTORY_INFO         *ReadDirInfo,\r
+  OUT     UDF_FILE_IDENTIFIER_DESCRIPTOR  **FoundFid\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UDF_READ_FILE_INFO              ReadFileInfo;\r
+  UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc;\r
+\r
+  if (ReadDirInfo->DirectoryData == NULL) {\r
+    //\r
+    // The directory's recorded data has not been read yet. So let's cache it\r
+    // into memory and the next calls won't need to read it again.\r
+    //\r
+    ReadFileInfo.Flags = READ_FILE_ALLOCATE_AND_READ;\r
+\r
+    Status = ReadFile (\r
+      BlockIo,\r
+      DiskIo,\r
+      Volume,\r
+      ParentIcb,\r
+      FileEntryData,\r
+      &ReadFileInfo\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Fill in ReadDirInfo structure with the read directory's data information.\r
+    //\r
+    ReadDirInfo->DirectoryData = ReadFileInfo.FileData;\r
+    ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;\r
+  }\r
+\r
+  do {\r
+    if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {\r
+      //\r
+      // There are no longer FIDs for this directory. By returning\r
+      // EFI_DEVICE_ERROR to the callee will indicate end of directory\r
+      // listening.\r
+      //\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    //\r
+    // Get FID for this entry.\r
+    //\r
+    FileIdentifierDesc = GET_FID_FROM_ADS (ReadDirInfo->DirectoryData,\r
+                                           ReadDirInfo->FidOffset);\r
+    //\r
+    // Update FidOffset to point to next FID.\r
+    //\r
+    ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);\r
+  } while (IS_FID_DELETED_FILE (FileIdentifierDesc));\r
+\r
+  DuplicateFid (FileIdentifierDesc, FoundFid);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get a filename (encoded in OSTA-compressed format) from a File Identifier\r
+  Descriptor on an UDF volume.\r
+\r
+  @param[in]   FileIdentifierDesc  File Identifier Descriptor pointer.\r
+  @param[out]  FileName            Decoded filename.\r
+\r
+  @retval EFI_SUCCESS           Filename decoded and read.\r
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
+**/\r
+EFI_STATUS\r
+GetFileNameFromFid (\r
+  IN   UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc,\r
+  OUT  CHAR16                          *FileName\r
+  )\r
+{\r
+  UINT8 *OstaCompressed;\r
+  UINT8 CompressionId;\r
+  UINT8 Length;\r
+  UINTN Index;\r
+\r
+  OstaCompressed =\r
+    (UINT8 *)(\r
+      (UINT8 *)FileIdentifierDesc->Data +\r
+      FileIdentifierDesc->LengthOfImplementationUse\r
+      );\r
+\r
+  CompressionId = OstaCompressed[0];\r
+  if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  //\r
+  // Decode filename.\r
+  //\r
+  Length = FileIdentifierDesc->LengthOfFileIdentifier;\r
+  for (Index = 1; Index < Length; Index++) {\r
+    if (CompressionId == 16) {\r
+      *FileName = OstaCompressed[Index++] << 8;\r
+    } else {\r
+      *FileName = 0;\r
+    }\r
+\r
+    if (Index < Length) {\r
+      *FileName |= OstaCompressed[Index];\r
+    }\r
+\r
+    FileName++;\r
+  }\r
+\r
+  *FileName = L'\0';\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Resolve a symlink file on an UDF volume.\r
+\r
+  @param[in]   BlockIo        BlockIo interface.\r
+  @param[in]   DiskIo         DiskIo interface.\r
+  @param[in]   Volume         UDF volume information structure.\r
+  @param[in]   Parent         Parent file.\r
+  @param[in]   FileEntryData  FE/EFE structure pointer.\r
+  @param[out]  File           Resolved file.\r
+\r
+  @retval EFI_SUCCESS          Symlink file resolved.\r
+  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+ResolveSymlink (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN   UDF_VOLUME_INFO        *Volume,\r
+  IN   UDF_FILE_INFO          *Parent,\r
+  IN   VOID                   *FileEntryData,\r
+  OUT  UDF_FILE_INFO          *File\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UDF_READ_FILE_INFO  ReadFileInfo;\r
+  UINT8               *Data;\r
+  UINT64              Length;\r
+  UINT8               *EndData;\r
+  UDF_PATH_COMPONENT  *PathComp;\r
+  UINT8               PathCompLength;\r
+  CHAR16              FileName[UDF_FILENAME_LENGTH];\r
+  CHAR16              *C;\r
+  UINTN               Index;\r
+  UINT8               CompressionId;\r
+  UDF_FILE_INFO       PreviousFile;\r
+\r
+  //\r
+  // Symlink files on UDF volumes do not contain so much data other than\r
+  // Path Components which resolves to real filenames, so it's OK to read in\r
+  // all its data here -- usually the data will be inline with the FE/EFE for\r
+  // lower filenames.\r
+  //\r
+  ReadFileInfo.Flags = READ_FILE_ALLOCATE_AND_READ;\r
+\r
+  Status = ReadFile (\r
+    BlockIo,\r
+    DiskIo,\r
+    Volume,\r
+    &Parent->FileIdentifierDesc->Icb,\r
+    FileEntryData,\r
+    &ReadFileInfo\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Length = ReadFileInfo.ReadLength;\r
+\r
+  Data = (UINT8 *)ReadFileInfo.FileData;\r
+  EndData = Data + Length;\r
+\r
+  CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));\r
+\r
+  for (;;) {\r
+    PathComp = (UDF_PATH_COMPONENT *)Data;\r
+\r
+    PathCompLength = PathComp->LengthOfComponentIdentifier;\r
+\r
+    switch (PathComp->ComponentType) {\r
+    case 1:\r
+      //\r
+      // This Path Component specifies the root directory hierarchy subject to\r
+      // agreement between the originator and recipient of the medium. Skip it.\r
+      //\r
+      // Fall through.\r
+      //\r
+    case 2:\r
+      //\r
+      // "\\." of the current directory. Read next Path Component.\r
+      //\r
+      goto Next_Path_Component;\r
+    case 3:\r
+      //\r
+      // ".." (parent directory). Go to it.\r
+      //\r
+      CopyMem ((VOID *)FileName, L"..", 6);\r
+      break;\r
+    case 4:\r
+      //\r
+      // "." (current file). Duplicate both FE/EFE and FID of this file.\r
+      //\r
+      DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);\r
+      DuplicateFid (PreviousFile.FileIdentifierDesc,\r
+                    &File->FileIdentifierDesc);\r
+      goto Next_Path_Component;\r
+    case 5:\r
+      //\r
+      // This Path Component identifies an object, either a file or a\r
+      // directory or an alias.\r
+      //\r
+      // Decode it from the compressed data in ComponentIdentifier and find\r
+      // respective path.\r
+      //\r
+      CompressionId = PathComp->ComponentIdentifier[0];\r
+      if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
+        return EFI_VOLUME_CORRUPTED;\r
+      }\r
+\r
+      C = FileName;\r
+      for (Index = 1; Index < PathCompLength; Index++) {\r
+        if (CompressionId == 16) {\r
+          *C = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +\r
+                          Index) << 8;\r
+          Index++;\r
+        } else {\r
+          *C = 0;\r
+        }\r
+\r
+        if (Index < Length) {\r
+          *C |= *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index);\r
+        }\r
+\r
+        C++;\r
+      }\r
+\r
+      *C = L'\0';\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Find file from the read filename in symlink's file data.\r
+    //\r
+    Status = InternalFindFile (\r
+      BlockIo,\r
+      DiskIo,\r
+      Volume,\r
+      FileName,\r
+      &PreviousFile,\r
+      NULL,\r
+      File\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error_Find_File;\r
+    }\r
+\r
+  Next_Path_Component:\r
+    Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;\r
+    if (Data >= EndData) {\r
+      break;\r
+    }\r
+\r
+    if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
+                    sizeof (UDF_FILE_INFO)) != 0) {\r
+      CleanupFileInformation (&PreviousFile);\r
+    }\r
+\r
+    CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));\r
+  }\r
+\r
+  //\r
+  // Unmap the symlink file.\r
+  //\r
+  FreePool (ReadFileInfo.FileData);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Error_Find_File:\r
+  if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
+                  sizeof (UDF_FILE_INFO)) != 0) {\r
+    CleanupFileInformation (&PreviousFile);\r
+  }\r
+\r
+  FreePool (ReadFileInfo.FileData);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Clean up in-memory UDF volume information.\r
+\r
+  @param[in] Volume Volume information pointer.\r
+\r
+**/\r
+VOID\r
+CleanupVolumeInformation (\r
+  IN UDF_VOLUME_INFO *Volume\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  if (Volume->LogicalVolDescs != NULL) {\r
+    for (Index = 0; Index < Volume->LogicalVolDescsNo; Index++) {\r
+      FreePool ((VOID *)Volume->LogicalVolDescs[Index]);\r
+    }\r
+    FreePool ((VOID *)Volume->LogicalVolDescs);\r
+  }\r
+\r
+  if (Volume->PartitionDescs != NULL) {\r
+    for (Index = 0; Index < Volume->PartitionDescsNo; Index++) {\r
+      FreePool ((VOID *)Volume->PartitionDescs[Index]);\r
+    }\r
+    FreePool ((VOID *)Volume->PartitionDescs);\r
+  }\r
+\r
+  if (Volume->FileSetDescs != NULL) {\r
+    for (Index = 0; Index < Volume->FileSetDescsNo; Index++) {\r
+      FreePool ((VOID *)Volume->FileSetDescs[Index]);\r
+    }\r
+    FreePool ((VOID *)Volume->FileSetDescs);\r
+  }\r
+\r
+  ZeroMem ((VOID *)Volume, sizeof (UDF_VOLUME_INFO));\r
+}\r
+\r
+/**\r
+  Clean up in-memory UDF file information.\r
+\r
+  @param[in] File File information pointer.\r
+\r
+**/\r
+VOID\r
+CleanupFileInformation (\r
+  IN UDF_FILE_INFO *File\r
+  )\r
+{\r
+  if (File->FileEntry != NULL) {\r
+    FreePool (File->FileEntry);\r
+  }\r
+  if (File->FileIdentifierDesc != NULL) {\r
+    FreePool ((VOID *)File->FileIdentifierDesc);\r
+  }\r
+\r
+  ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));\r
+}\r
+\r
+/**\r
+  Find a file from its absolute path on an UDF volume.\r
+\r
+  @param[in]   BlockIo  BlockIo interface.\r
+  @param[in]   DiskIo   DiskIo interface.\r
+  @param[in]   Volume   UDF volume information structure.\r
+  @param[in]   File     File information structure.\r
+  @param[out]  Size     Size of the file.\r
+\r
+  @retval EFI_SUCCESS          File size calculated and set in @p Size.\r
+  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFileSize (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN   UDF_VOLUME_INFO        *Volume,\r
+  IN   UDF_FILE_INFO          *File,\r
+  OUT  UINT64                 *Size\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UDF_READ_FILE_INFO  ReadFileInfo;\r
+\r
+  ReadFileInfo.Flags = READ_FILE_GET_FILESIZE;\r
+\r
+  Status = ReadFile (\r
+    BlockIo,\r
+    DiskIo,\r
+    Volume,\r
+    &File->FileIdentifierDesc->Icb,\r
+    File->FileEntry,\r
+    &ReadFileInfo\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *Size = ReadFileInfo.ReadLength;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set information about a file on an UDF volume.\r
+\r
+  @param[in]      File        File pointer.\r
+  @param[in]      FileSize    Size of the file.\r
+  @param[in]      FileName    Filename of the file.\r
+  @param[in out]  BufferSize  Size of the returned file infomation.\r
+  @param[out]     Buffer      Data of the returned file information.\r
+\r
+  @retval EFI_SUCCESS          File information set.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+SetFileInfo (\r
+  IN      UDF_FILE_INFO  *File,\r
+  IN      UINT64         FileSize,\r
+  IN      CHAR16         *FileName,\r
+  IN OUT  UINTN          *BufferSize,\r
+  OUT     VOID           *Buffer\r
+  )\r
+{\r
+  UINTN                    FileInfoLength;\r
+  EFI_FILE_INFO            *FileInfo;\r
+  UDF_FILE_ENTRY           *FileEntry;\r
+  UDF_EXTENDED_FILE_ENTRY  *ExtendedFileEntry;\r
+\r
+  //\r
+  // Calculate the needed size for the EFI_FILE_INFO structure.\r
+  //\r
+  FileInfoLength = sizeof (EFI_FILE_INFO) + (FileName ?\r
+                                             StrSize (FileName) :\r
+                                             sizeof (CHAR16));\r
+  if (*BufferSize < FileInfoLength) {\r
+    //\r
+    // The given Buffer has no size enough for EFI_FILE_INFO structure.\r
+    //\r
+    *BufferSize = FileInfoLength;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  //\r
+  // Buffer now contains room enough to store EFI_FILE_INFO structure.\r
+  // Now, fill it in with all necessary information about the file.\r
+  //\r
+  FileInfo = (EFI_FILE_INFO *)Buffer;\r
+  FileInfo->Size         = FileInfoLength;\r
+  FileInfo->Attribute    &= ~EFI_FILE_VALID_ATTR;\r
+  FileInfo->Attribute    |= EFI_FILE_READ_ONLY;\r
+\r
+  if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {\r
+    FileInfo->Attribute |= EFI_FILE_DIRECTORY;\r
+  } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {\r
+    FileInfo->Attribute |= EFI_FILE_ARCHIVE;\r
+  }\r
+\r
+  if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {\r
+    FileInfo->Attribute |= EFI_FILE_HIDDEN;\r
+  }\r
+\r
+  if (IS_FE (File->FileEntry)) {\r
+    FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;\r
+\r
+    //\r
+    // Check if FE has the system attribute set.\r
+    //\r
+    if (FileEntry->IcbTag.Flags & (1 << 10)) {\r
+      FileInfo->Attribute |= EFI_FILE_SYSTEM;\r
+    }\r
+\r
+    FileInfo->FileSize      = FileSize;\r
+    FileInfo->PhysicalSize  = FileSize;\r
+\r
+    FileInfo->CreateTime.Year        = FileEntry->AccessTime.Year;\r
+    FileInfo->CreateTime.Month       = FileEntry->AccessTime.Month;\r
+    FileInfo->CreateTime.Day         = FileEntry->AccessTime.Day;\r
+    FileInfo->CreateTime.Hour        = FileEntry->AccessTime.Hour;\r
+    FileInfo->CreateTime.Minute      = FileEntry->AccessTime.Second;\r
+    FileInfo->CreateTime.Second      = FileEntry->AccessTime.Second;\r
+    FileInfo->CreateTime.Nanosecond  =\r
+                                   FileEntry->AccessTime.HundredsOfMicroseconds;\r
+\r
+    FileInfo->LastAccessTime.Year        =\r
+                                   FileEntry->AccessTime.Year;\r
+    FileInfo->LastAccessTime.Month       =\r
+                                   FileEntry->AccessTime.Month;\r
+    FileInfo->LastAccessTime.Day         =\r
+                                   FileEntry->AccessTime.Day;\r
+    FileInfo->LastAccessTime.Hour        =\r
+                                   FileEntry->AccessTime.Hour;\r
+    FileInfo->LastAccessTime.Minute      =\r
+                                   FileEntry->AccessTime.Minute;\r
+    FileInfo->LastAccessTime.Second      =\r
+                                   FileEntry->AccessTime.Second;\r
+    FileInfo->LastAccessTime.Nanosecond  =\r
+                                   FileEntry->AccessTime.HundredsOfMicroseconds;\r
+  } else if (IS_EFE (File->FileEntry)) {\r
+    ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;\r
+\r
+    //\r
+    // Check if EFE has the system attribute set.\r
+    //\r
+    if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {\r
+      FileInfo->Attribute |= EFI_FILE_SYSTEM;\r
+    }\r
+\r
+    FileInfo->FileSize      = FileSize;\r
+    FileInfo->PhysicalSize  = FileSize;\r
+\r
+    FileInfo->CreateTime.Year        = ExtendedFileEntry->CreationTime.Year;\r
+    FileInfo->CreateTime.Month       = ExtendedFileEntry->CreationTime.Month;\r
+    FileInfo->CreateTime.Day         = ExtendedFileEntry->CreationTime.Day;\r
+    FileInfo->CreateTime.Hour        = ExtendedFileEntry->CreationTime.Hour;\r
+    FileInfo->CreateTime.Minute      = ExtendedFileEntry->CreationTime.Second;\r
+    FileInfo->CreateTime.Second      = ExtendedFileEntry->CreationTime.Second;\r
+    FileInfo->CreateTime.Nanosecond  =\r
+                           ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;\r
+\r
+    FileInfo->LastAccessTime.Year        =\r
+                           ExtendedFileEntry->AccessTime.Year;\r
+    FileInfo->LastAccessTime.Month       =\r
+                           ExtendedFileEntry->AccessTime.Month;\r
+    FileInfo->LastAccessTime.Day         =\r
+                           ExtendedFileEntry->AccessTime.Day;\r
+    FileInfo->LastAccessTime.Hour        =\r
+                           ExtendedFileEntry->AccessTime.Hour;\r
+    FileInfo->LastAccessTime.Minute      =\r
+                           ExtendedFileEntry->AccessTime.Minute;\r
+    FileInfo->LastAccessTime.Second      =\r
+                           ExtendedFileEntry->AccessTime.Second;\r
+    FileInfo->LastAccessTime.Nanosecond  =\r
+                           ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;\r
+  }\r
+\r
+  FileInfo->CreateTime.TimeZone      = EFI_UNSPECIFIED_TIMEZONE;\r
+  FileInfo->CreateTime.Daylight      = EFI_TIME_ADJUST_DAYLIGHT;\r
+  FileInfo->LastAccessTime.TimeZone  = EFI_UNSPECIFIED_TIMEZONE;\r
+  FileInfo->LastAccessTime.Daylight  = EFI_TIME_ADJUST_DAYLIGHT;\r
+\r
+  CopyMem ((VOID *)&FileInfo->ModificationTime,\r
+           (VOID *)&FileInfo->LastAccessTime,\r
+           sizeof (EFI_TIME));\r
+\r
+  if (FileName != NULL) {\r
+    StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);\r
+  } else {\r
+    FileInfo->FileName[0] = '\0';\r
+  }\r
+\r
+  *BufferSize = FileInfoLength;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get volume and free space size information of an UDF volume.\r
+\r
+  @param[in]   BlockIo        BlockIo interface.\r
+  @param[in]   DiskIo         DiskIo interface.\r
+  @param[in]   Volume         UDF volume information structure.\r
+  @param[out]  VolumeSize     Volume size.\r
+  @param[out]  FreeSpaceSize  Free space size.\r
+\r
+  @retval EFI_SUCCESS          Volume and free space size calculated.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The volume and free space size were not\r
+                               calculated due to lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+GetVolumeSize (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN   UDF_VOLUME_INFO        *Volume,\r
+  OUT  UINT64                 *VolumeSize,\r
+  OUT  UINT64                 *FreeSpaceSize\r
+  )\r
+{\r
+  UDF_EXTENT_AD                 ExtentAd;\r
+  UINT32                        LogicalBlockSize;\r
+  UINT64                        Lsn;\r
+  EFI_STATUS                    Status;\r
+  UDF_LOGICAL_VOLUME_INTEGRITY  *LogicalVolInt;\r
+  UINTN                         Index;\r
+  UINTN                         Length;\r
+  UINT32                        LsnsNo;\r
+\r
+  *VolumeSize     = 0;\r
+  *FreeSpaceSize  = 0;\r
+\r
+  for (Index = 0; Index < Volume->LogicalVolDescsNo; Index++) {\r
+    CopyMem ((VOID *)&ExtentAd,\r
+             (VOID *)&Volume->LogicalVolDescs[Index]->IntegritySequenceExtent,\r
+             sizeof (UDF_EXTENT_AD));\r
+    if (ExtentAd.ExtentLength == 0) {\r
+      continue;\r
+    }\r
+\r
+    LogicalBlockSize = LV_BLOCK_SIZE (Volume, Index);\r
+\r
+  Read_Next_Sequence:\r
+    LogicalVolInt = (UDF_LOGICAL_VOLUME_INTEGRITY *)\r
+      AllocatePool (ExtentAd.ExtentLength);\r
+    if (LogicalVolInt == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Lsn = (UINT64)ExtentAd.ExtentLocation;\r
+\r
+    Status = DiskIo->ReadDisk (\r
+      DiskIo,\r
+      BlockIo->Media->MediaId,\r
+      MultU64x32 (Lsn, LogicalBlockSize),\r
+      ExtentAd.ExtentLength,\r
+      (VOID *)LogicalVolInt\r
+      );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool ((VOID *)LogicalVolInt);\r
+      return Status;\r
+    }\r
+\r
+    if (!IS_LVID (LogicalVolInt)) {\r
+      FreePool ((VOID *)LogicalVolInt);\r
+      return EFI_VOLUME_CORRUPTED;\r
+    }\r
+\r
+    Length = LogicalVolInt->NumberOfPartitions;\r
+    for (Index = 0; Index < Length; Index += sizeof (UINT32)) {\r
+      LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);\r
+      if (LsnsNo == 0xFFFFFFFFUL) {\r
+        //\r
+        // Size not specified.\r
+        //\r
+        continue;\r
+      }\r
+\r
+      *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);\r
+    }\r
+\r
+    Length = (LogicalVolInt->NumberOfPartitions * sizeof (UINT32)) << 1;\r
+    for (; Index < Length; Index += sizeof (UINT32)) {\r
+      LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);\r
+      if (LsnsNo == 0xFFFFFFFFUL) {\r
+        //\r
+        // Size not specified.\r
+        //\r
+        continue;\r
+      }\r
+\r
+      *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);\r
+    }\r
+\r
+    CopyMem ((VOID *)&ExtentAd,(VOID *)&LogicalVolInt->NextIntegrityExtent,\r
+             sizeof (UDF_EXTENT_AD));\r
+    if (ExtentAd.ExtentLength > 0) {\r
+      FreePool ((VOID *)LogicalVolInt);\r
+      goto Read_Next_Sequence;\r
+    }\r
+\r
+    FreePool ((VOID *)LogicalVolInt);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Seek a file and read its data into memory on an UDF volume.\r
+\r
+  @param[in]      BlockIo       BlockIo interface.\r
+  @param[in]      DiskIo        DiskIo interface.\r
+  @param[in]      Volume        UDF volume information structure.\r
+  @param[in]      File          File information structure.\r
+  @param[in]      FileSize      Size of the file.\r
+  @param[in out]  FilePosition  File position.\r
+  @param[in out]  Buffer        File data.\r
+  @param[in out]  BufferSize    Read size.\r
+\r
+  @retval EFI_SUCCESS          File seeked and read.\r
+  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack\r
+                               of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadFileData (\r
+  IN      EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN      EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN      UDF_VOLUME_INFO        *Volume,\r
+  IN      UDF_FILE_INFO          *File,\r
+  IN      UINT64                 FileSize,\r
+  IN OUT  UINT64                 *FilePosition,\r
+  IN OUT  VOID                   *Buffer,\r
+  IN OUT  UINT64                 *BufferSize\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UDF_READ_FILE_INFO  ReadFileInfo;\r
+\r
+  ReadFileInfo.Flags         = READ_FILE_SEEK_AND_READ;\r
+  ReadFileInfo.FilePosition  = *FilePosition;\r
+  ReadFileInfo.FileData      = Buffer;\r
+  ReadFileInfo.FileDataSize  = *BufferSize;\r
+  ReadFileInfo.FileSize      = FileSize;\r
+\r
+  Status = ReadFile (\r
+                 BlockIo,\r
+                 DiskIo,\r
+                 Volume,\r
+                 &File->FileIdentifierDesc->Icb,\r
+                 File->FileEntry,\r
+                 &ReadFileInfo\r
+                 );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *BufferSize    = ReadFileInfo.FileDataSize;\r
+  *FilePosition  = ReadFileInfo.FilePosition;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check if ControllerHandle supports an UDF file system.\r
+\r
+  @param[in]  This                Protocol instance pointer.\r
+  @param[in]  ControllerHandle    Handle of device to test.\r
+\r
+  @retval EFI_SUCCESS             UDF file system found.\r
+  @retval EFI_UNSUPPORTED         UDF file system not found.\r
+\r
+**/\r
+EFI_STATUS\r
+SupportUdfFileSystem (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode;\r
+  EFI_DEVICE_PATH_PROTOCOL  *LastDevicePathNode;\r
+  EFI_GUID                  *VendorDefinedGuid;\r
+  EFI_GUID                  UdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;\r
+\r
+  //\r
+  // Open Device Path protocol on ControllerHandle\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+    ControllerHandle,\r
+    &gEfiDevicePathProtocolGuid,\r
+    (VOID **)&DevicePath,\r
+    This->DriverBindingHandle,\r
+    ControllerHandle,\r
+    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  //\r
+  // Get last Device Path node\r
+  //\r
+  LastDevicePathNode = NULL;\r
+  DevicePathNode = DevicePath;\r
+  while (!IsDevicePathEnd (DevicePathNode)) {\r
+    LastDevicePathNode = DevicePathNode;\r
+    DevicePathNode = NextDevicePathNode (DevicePathNode);\r
+  }\r
+  //\r
+  // Check if last Device Path node contains a Vendor-Defined Media Device Path\r
+  // of an UDF file system.\r
+  //\r
+  if (LastDevicePathNode != NULL &&\r
+      DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&\r
+      DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP) {\r
+    VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +\r
+                                     OFFSET_OF (VENDOR_DEVICE_PATH, Guid));\r
+    if (CompareGuid (VendorDefinedGuid, &UdfDevPathGuid)) {\r
+      Status = EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Close Device Path protocol on ControllerHandle\r
+  //\r
+  gBS->CloseProtocol (\r
+    ControllerHandle,\r
+    &gEfiDevicePathProtocolGuid,\r
+    This->DriverBindingHandle,\r
+    ControllerHandle\r
+    );\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c b/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c
new file mode 100644 (file)
index 0000000..49dc707
--- /dev/null
@@ -0,0 +1,344 @@
+/** @file\r
+  UDF/ECMA-167 file system driver.\r
+\r
+  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include "Udf.h"\r
+\r
+//\r
+// UDF filesystem driver's Global Variables.\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gUdfDriverBinding = {\r
+  UdfDriverBindingSupported,\r
+  UdfDriverBindingStart,\r
+  UdfDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gUdfSimpleFsTemplate = {\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,\r
+  UdfOpenVolume\r
+};\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
+  than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be\r
+  supported.\r
+\r
+  @param[in]  This                Protocol instance pointer.\r
+  @param[in]  ControllerHandle    Handle of device to test.\r
+  @param[in]  RemainingDevicePath Optional parameter use to pick a specific\r
+                                  child device to start.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+  @retval other               This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_DISK_IO_PROTOCOL  *DiskIo;\r
+\r
+  //\r
+  // Open DiskIo protocol on ControllerHandle\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+    ControllerHandle,\r
+    &gEfiDiskIoProtocolGuid,\r
+    (VOID **)&DiskIo,\r
+    This->DriverBindingHandle,\r
+    ControllerHandle,\r
+    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Close DiskIo protocol on ControllerHandle\r
+  //\r
+  gBS->CloseProtocol (\r
+    ControllerHandle,\r
+    &gEfiDiskIoProtocolGuid,\r
+    This->DriverBindingHandle,\r
+    ControllerHandle\r
+    );\r
+\r
+  //\r
+  // Test whether ControllerHandle supports BlockIo protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+    ControllerHandle,\r
+    &gEfiBlockIoProtocolGuid,\r
+    NULL,\r
+    This->DriverBindingHandle,\r
+    ControllerHandle,\r
+    EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+    );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Start this driver on ControllerHandle by opening a Block IO or a Block IO2\r
+  or both, and Disk IO protocol, reading Device Path, and creating a child\r
+  handle with a Disk IO and device path protocol.\r
+\r
+  @param[in]  This                 Protocol instance pointer.\r
+  @param[in]  ControllerHandle     Handle of device to bind driver to\r
+  @param[in]  RemainingDevicePath  Optional parameter use to pick a specific\r
+                                   child device to start.\r
+\r
+  @retval EFI_SUCCESS          This driver is added to ControllerHandle.\r
+  @retval EFI_ALREADY_STARTED  This driver is already running on\r
+                               ControllerHandle.\r
+  @retval other                This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_TPL                     OldTpl;\r
+  EFI_STATUS                  Status;\r
+  EFI_BLOCK_IO_PROTOCOL       *BlockIo;\r
+  EFI_DISK_IO_PROTOCOL        *DiskIo;\r
+  PRIVATE_UDF_SIMPLE_FS_DATA  *PrivFsData;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  //\r
+  // Open BlockIo protocol on ControllerHandle\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+    ControllerHandle,\r
+    &gEfiBlockIoProtocolGuid,\r
+    (VOID **)&BlockIo,\r
+    This->DriverBindingHandle,\r
+    ControllerHandle,\r
+    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Open DiskIo protocol on ControllerHandle\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+    ControllerHandle,\r
+    &gEfiDiskIoProtocolGuid,\r
+    (VOID **)&DiskIo,\r
+    This->DriverBindingHandle,\r
+    ControllerHandle,\r
+    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Check if ControllerHandle supports an UDF file system\r
+  //\r
+  Status = SupportUdfFileSystem (This, ControllerHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Initialize private file system structure\r
+  //\r
+  PrivFsData =\r
+    (PRIVATE_UDF_SIMPLE_FS_DATA *)\r
+    AllocateZeroPool (sizeof (PRIVATE_UDF_SIMPLE_FS_DATA));\r
+  if (PrivFsData == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Create new child handle\r
+  //\r
+  PrivFsData->Signature = PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE;\r
+  PrivFsData->BlockIo   = BlockIo;\r
+  PrivFsData->DiskIo    = DiskIo;\r
+  PrivFsData->Handle    = ControllerHandle;\r
+\r
+  //\r
+  // Set up SimpleFs protocol\r
+  //\r
+  CopyMem ((VOID *)&PrivFsData->SimpleFs, (VOID *)&gUdfSimpleFsTemplate,\r
+           sizeof (EFI_SIMPLE_FILE_SYSTEM_PROTOCOL));\r
+\r
+  //\r
+  // Install child handle\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+    &PrivFsData->Handle,\r
+    &gEfiSimpleFileSystemProtocolGuid,\r
+    &PrivFsData->SimpleFs,\r
+    NULL\r
+    );\r
+\r
+Exit:\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Close DiskIo protocol on ControllerHandle\r
+    //\r
+    gBS->CloseProtocol (\r
+      ControllerHandle,\r
+      &gEfiDiskIoProtocolGuid,\r
+      This->DriverBindingHandle,\r
+      ControllerHandle\r
+      );\r
+    //\r
+    // Close BlockIo protocol on ControllerHandle\r
+    //\r
+    gBS->CloseProtocol (\r
+      ControllerHandle,\r
+      &gEfiBlockIoProtocolGuid,\r
+      This->DriverBindingHandle,\r
+      ControllerHandle\r
+      );\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stop this driver on ControllerHandle. Support stopping any child handles\r
+  created by this driver.\r
+\r
+  @param  This              Protocol instance pointer.\r
+  @param  ControllerHandle  Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
+  @retval other             This driver was not removed from this device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN  EFI_HANDLE                    ControllerHandle,\r
+  IN  UINTN                         NumberOfChildren,\r
+  IN  EFI_HANDLE                    *ChildHandleBuffer\r
+  )\r
+{\r
+  PRIVATE_UDF_SIMPLE_FS_DATA        *PrivFsData;\r
+  EFI_STATUS                        Status;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *SimpleFs;\r
+\r
+  //\r
+  // Open SimpleFs protocol on ControllerHandle\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+    ControllerHandle,\r
+    &gEfiSimpleFileSystemProtocolGuid,\r
+    (VOID **)&SimpleFs,\r
+    This->DriverBindingHandle,\r
+    ControllerHandle,\r
+    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+    );\r
+  if (!EFI_ERROR (Status)) {\r
+    PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (SimpleFs);\r
+\r
+    //\r
+    // Uninstall child handle\r
+    //\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+      PrivFsData->Handle,\r
+      &gEfiSimpleFileSystemProtocolGuid,\r
+      &PrivFsData->SimpleFs,\r
+      NULL\r
+      );\r
+\r
+    //\r
+    // Check if there's any open file. If so, clean them up.\r
+    //\r
+    if (PrivFsData->OpenFiles > 0) {\r
+      CleanupVolumeInformation (&PrivFsData->Volume);\r
+    }\r
+\r
+    FreePool ((VOID *)PrivFsData);\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Close DiskIo protocol on ControllerHandle\r
+    //\r
+    gBS->CloseProtocol (\r
+      ControllerHandle,\r
+      &gEfiDiskIoProtocolGuid,\r
+      This->DriverBindingHandle,\r
+      ControllerHandle\r
+      );\r
+    //\r
+    // Close BlockIo protocol on ControllerHandle\r
+    //\r
+    gBS->CloseProtocol (\r
+      ControllerHandle,\r
+      &gEfiBlockIoProtocolGuid,\r
+      This->DriverBindingHandle,\r
+      ControllerHandle\r
+      );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The user Entry Point for UDF file system driver. The user code starts with\r
+  this function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeUdf (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+    ImageHandle,\r
+    SystemTable,\r
+    &gUdfDriverBinding,\r
+    ImageHandle,\r
+    &gUdfComponentName,\r
+    &gUdfComponentName2\r
+    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h b/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h
new file mode 100644 (file)
index 0000000..240d420
--- /dev/null
@@ -0,0 +1,1244 @@
+/** @file\r
+  UDF/ECMA-167 file system driver.\r
+\r
+  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef _UDF_H_\r
+#define _UDF_H_\r
+\r
+#include <Uefi.h>\r
+#include <Base.h>\r
+\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/ComponentName.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/DriverBinding.h>\r
+#include <Protocol/DiskIo.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/FileSystemInfo.h>\r
+#include <Guid/FileSystemVolumeLabelInfo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DevicePathLib.h>\r
+\r
+#include <IndustryStandard/ElTorito.h>\r
+#include <IndustryStandard/Udf.h>\r
+\r
+//\r
+// C5BD4D42-1A76-4996-8956-73CDA326CD0A\r
+//\r
+#define EFI_UDF_DEVICE_PATH_GUID                        \\r
+  { 0xC5BD4D42, 0x1A76, 0x4996,                         \\r
+    { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A }  \\r
+  }\r
+\r
+#define UDF_DEFAULT_LV_NUM 0\r
+\r
+#define IS_PVD(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 1))\r
+#define IS_PD(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 5))\r
+#define IS_LVD(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 6))\r
+#define IS_TD(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 8))\r
+#define IS_FSD(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 256))\r
+#define IS_FE(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 261))\r
+#define IS_EFE(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 266))\r
+#define IS_FID(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 257))\r
+#define IS_AED(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 258))\r
+#define IS_LVID(_Pointer) \\r
+  ((BOOLEAN)(_GET_TAG_ID (_Pointer) == 9))\r
+\r
+#define _GET_FILETYPE(_Pointer) \\r
+  (IS_FE (_Pointer) ? \\r
+   (((UDF_FILE_ENTRY *)(_Pointer))->IcbTag.FileType) \\r
+   : \\r
+   (((UDF_EXTENDED_FILE_ENTRY *)(_Pointer))->IcbTag.FileType))\r
+\r
+#define IS_FE_DIRECTORY(_Pointer) \\r
+  ((BOOLEAN)(_GET_FILETYPE (_Pointer) == 4))\r
+#define IS_FE_STANDARD_FILE(_Pointer) \\r
+  ((BOOLEAN)(_GET_FILETYPE (_Pointer) == 5))\r
+#define IS_FE_SYMLINK(_Pointer) \\r
+  ((BOOLEAN)(_GET_FILETYPE (_Pointer) == 12))\r
+\r
+#define HIDDEN_FILE     (1 << 0)\r
+#define DIRECTORY_FILE  (1 << 1)\r
+#define DELETED_FILE    (1 << 2)\r
+#define PARENT_FILE     (1 << 3)\r
+\r
+#define _GET_FILE_CHARS(_Pointer) \\r
+  (((UDF_FILE_IDENTIFIER_DESCRIPTOR *)(_Pointer))->FileCharacteristics)\r
+\r
+#define IS_FID_HIDDEN_FILE(_Pointer) \\r
+  ((BOOLEAN)(_GET_FILE_CHARS (_Pointer) & HIDDEN_FILE))\r
+#define IS_FID_DIRECTORY_FILE(_Pointer) \\r
+  ((BOOLEAN)(_GET_FILE_CHARS (_Pointer) & DIRECTORY_FILE))\r
+#define IS_FID_DELETED_FILE(_Pointer) \\r
+  ((BOOLEAN)(_GET_FILE_CHARS (_Pointer) & DELETED_FILE))\r
+#define IS_FID_PARENT_FILE(_Pointer) \\r
+  ((BOOLEAN)(_GET_FILE_CHARS (_Pointer) & PARENT_FILE))\r
+#define IS_FID_NORMAL_FILE(_Pointer) \\r
+  ((BOOLEAN)(!IS_FID_DIRECTORY_FILE (_Pointer) && \\r
+         !IS_FID_PARENT_FILE (_Pointer)))\r
+\r
+typedef enum {\r
+  SHORT_ADS_SEQUENCE,\r
+  LONG_ADS_SEQUENCE,\r
+  EXTENDED_ADS_SEQUENCE,\r
+  INLINE_DATA\r
+} UDF_FE_RECORDING_FLAGS;\r
+\r
+#define GET_FE_RECORDING_FLAGS(_Fe) \\r
+  ((UDF_FE_RECORDING_FLAGS)((UDF_ICB_TAG *)( \\r
+                  (UINT8 *)(_Fe) + \\r
+                  sizeof (UDF_DESCRIPTOR_TAG)))->Flags & 0x07)\r
+\r
+typedef enum {\r
+  EXTENT_RECORDED_AND_ALLOCATED,\r
+  EXTENT_NOT_RECORDED_BUT_ALLOCATED,\r
+  EXTENT_NOT_RECORDED_NOT_ALLOCATED,\r
+  EXTENT_IS_NEXT_EXTENT,\r
+} UDF_EXTENT_FLAGS;\r
+\r
+#define AD_LENGTH(_RecFlags) \\r
+  ((_RecFlags) == SHORT_ADS_SEQUENCE ? \\r
+   ((UINT64)(sizeof (UDF_SHORT_ALLOCATION_DESCRIPTOR))) : \\r
+   ((UINT64)(sizeof (UDF_LONG_ALLOCATION_DESCRIPTOR))))\r
+\r
+#define GET_EXTENT_FLAGS(_RecFlags, _Ad) \\r
+  ((_RecFlags) == SHORT_ADS_SEQUENCE ? \\r
+   ((UDF_EXTENT_FLAGS)((((UDF_SHORT_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength >> \\r
+            30) & 0x3)) : \\r
+   ((UDF_EXTENT_FLAGS)((((UDF_LONG_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength >> \\r
+            30) & 0x3)))\r
+\r
+#define GET_EXTENT_LENGTH(_RecFlags, _Ad) \\r
+  ((_RecFlags) == SHORT_ADS_SEQUENCE ? \\r
+   ((UINT32)((((UDF_SHORT_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength & \\r
+          ~0xC0000000UL))) : \\r
+   ((UINT32)((((UDF_LONG_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength & \\r
+          ~0xC0000000UL))))\r
+\r
+#define UDF_FILENAME_LENGTH  128\r
+#define UDF_PATH_LENGTH      512\r
+\r
+#define GET_FID_FROM_ADS(_Data, _Offs) \\r
+  ((UDF_FILE_IDENTIFIER_DESCRIPTOR *)((UINT8 *)(_Data) + (_Offs)))\r
+\r
+#define IS_VALID_COMPRESSION_ID(_CompId) \\r
+  ((BOOLEAN)((_CompId) == 8 || (_CompId) == 16))\r
+\r
+#define LV_BLOCK_SIZE(_Vol, _LvNum) \\r
+  (_Vol)->LogicalVolDescs[(_LvNum)]->LogicalBlockSize\r
+\r
+#define UDF_STANDARD_IDENTIFIER_LENGTH   5\r
+\r
+#define LV_UDF_REVISION(_Lv) \\r
+  *(UINT16 *)(UINTN)(_Lv)->DomainIdentifier.IdentifierSuffix\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  UINT8 StandardIdentifier[UDF_STANDARD_IDENTIFIER_LENGTH];\r
+} UDF_STANDARD_IDENTIFIER;\r
+\r
+#pragma pack()\r
+\r
+typedef enum {\r
+  READ_FILE_GET_FILESIZE,\r
+  READ_FILE_ALLOCATE_AND_READ,\r
+  READ_FILE_SEEK_AND_READ,\r
+} UDF_READ_FILE_FLAGS;\r
+\r
+typedef struct {\r
+  VOID                 *FileData;\r
+  UDF_READ_FILE_FLAGS  Flags;\r
+  UINT64               FileDataSize;\r
+  UINT64               FilePosition;\r
+  UINT64               FileSize;\r
+  UINT64               ReadLength;\r
+} UDF_READ_FILE_INFO;\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  UINT8           CharacterSetType;\r
+  UINT8           CharacterSetInfo[63];\r
+} UDF_CHAR_SPEC;\r
+\r
+typedef struct {\r
+  UINT8           Flags;\r
+  UINT8           Identifier[23];\r
+  UINT8           IdentifierSuffix[8];\r
+} UDF_ENTITY_ID;\r
+\r
+typedef struct {\r
+  UINT16          TypeAndTimezone;\r
+  INT16           Year;\r
+  UINT8           Month;\r
+  UINT8           Day;\r
+  UINT8           Hour;\r
+  UINT8           Minute;\r
+  UINT8           Second;\r
+  UINT8           Centiseconds;\r
+  UINT8           HundredsOfMicroseconds;\r
+  UINT8           Microseconds;\r
+} UDF_TIMESTAMP;\r
+\r
+typedef struct {\r
+  UINT32        LogicalBlockNumber;\r
+  UINT16        PartitionReferenceNumber;\r
+} UDF_LB_ADDR;\r
+\r
+typedef struct {\r
+  UINT32                           ExtentLength;\r
+  UDF_LB_ADDR                      ExtentLocation;\r
+  UINT8                            ImplementationUse[6];\r
+} UDF_LONG_ALLOCATION_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UDF_DESCRIPTOR_TAG                 DescriptorTag;\r
+  UINT32                             PrevAllocationExtentDescriptor;\r
+  UINT32                             LengthOfAllocationDescriptors;\r
+} UDF_ALLOCATION_EXTENT_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UINT8                   StructureType;\r
+  UINT8                   StandardIdentifier[UDF_STANDARD_IDENTIFIER_LENGTH];\r
+  UINT8                   StructureVersion;\r
+  UINT8                   Reserved;\r
+  UINT8                   StructureData[2040];\r
+} UDF_VOLUME_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UDF_DESCRIPTOR_TAG         DescriptorTag;\r
+  UINT32                     VolumeDescriptorSequenceNumber;\r
+  UINT16                     PartitionFlags;\r
+  UINT16                     PartitionNumber;\r
+  UDF_ENTITY_ID              PartitionContents;\r
+  UINT8                      PartitionContentsUse[128];\r
+  UINT32                     AccessType;\r
+  UINT32                     PartitionStartingLocation;\r
+  UINT32                     PartitionLength;\r
+  UDF_ENTITY_ID              ImplementationIdentifier;\r
+  UINT8                      ImplementationUse[128];\r
+  UINT8                      Reserved[156];\r
+} UDF_PARTITION_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UDF_DESCRIPTOR_TAG              DescriptorTag;\r
+  UINT32                          VolumeDescriptorSequenceNumber;\r
+  UDF_CHAR_SPEC                   DescriptorCharacterSet;\r
+  UINT8                           LogicalVolumeIdentifier[128];\r
+  UINT32                          LogicalBlockSize;\r
+  UDF_ENTITY_ID                   DomainIdentifier;\r
+  UDF_LONG_ALLOCATION_DESCRIPTOR  LogicalVolumeContentsUse;\r
+  UINT32                          MapTableLength;\r
+  UINT32                          NumberOfPartitionMaps;\r
+  UDF_ENTITY_ID                   ImplementationIdentifier;\r
+  UINT8                           ImplementationUse[128];\r
+  UDF_EXTENT_AD                   IntegritySequenceExtent;\r
+  UINT8                           PartitionMaps[6];\r
+} UDF_LOGICAL_VOLUME_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UDF_DESCRIPTOR_TAG             DescriptorTag;\r
+  UDF_TIMESTAMP                  RecordingDateTime;\r
+  UINT32                         IntegrityType;\r
+  UDF_EXTENT_AD                  NextIntegrityExtent;\r
+  UINT8                          LogicalVolumeContentsUse[32];\r
+  UINT32                         NumberOfPartitions;\r
+  UINT32                         LengthOfImplementationUse;\r
+  UINT8                          Data[0];\r
+} UDF_LOGICAL_VOLUME_INTEGRITY;\r
+\r
+typedef struct {\r
+  UDF_DESCRIPTOR_TAG              DescriptorTag;\r
+  UDF_TIMESTAMP                   RecordingDateAndTime;\r
+  UINT16                          InterchangeLevel;\r
+  UINT16                          MaximumInterchangeLevel;\r
+  UINT32                          CharacterSetList;\r
+  UINT32                          MaximumCharacterSetList;\r
+  UINT32                          FileSetNumber;\r
+  UINT32                          FileSetDescriptorNumber;\r
+  UDF_CHAR_SPEC                   LogicalVolumeIdentifierCharacterSet;\r
+  UINT8                           LogicalVolumeIdentifier[128];\r
+  UDF_CHAR_SPEC                   FileSetCharacterSet;\r
+  UINT8                           FileSetIdentifier[32];\r
+  UINT8                           CopyrightFileIdentifier[32];\r
+  UINT8                           AbstractFileIdentifier[32];\r
+  UDF_LONG_ALLOCATION_DESCRIPTOR  RootDirectoryIcb;\r
+  UDF_ENTITY_ID                   DomainIdentifier;\r
+  UDF_LONG_ALLOCATION_DESCRIPTOR  NextExtent;\r
+  UDF_LONG_ALLOCATION_DESCRIPTOR  SystemStreamDirectoryIcb;\r
+  UINT8                           Reserved[32];\r
+} UDF_FILE_SET_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UINT32                            ExtentLength;\r
+  UINT32                            ExtentPosition;\r
+} UDF_SHORT_ALLOCATION_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UDF_DESCRIPTOR_TAG               DescriptorTag;\r
+  UINT16                           FileVersionNumber;\r
+  UINT8                            FileCharacteristics;\r
+  UINT8                            LengthOfFileIdentifier;\r
+  UDF_LONG_ALLOCATION_DESCRIPTOR   Icb;\r
+  UINT16                           LengthOfImplementationUse;\r
+  UINT8                            Data[0];\r
+} UDF_FILE_IDENTIFIER_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UINT32        PriorRecordNumberOfDirectEntries;\r
+  UINT16        StrategyType;\r
+  UINT16        StrategyParameter;\r
+  UINT16        MaximumNumberOfEntries;\r
+  UINT8         Reserved;\r
+  UINT8         FileType;\r
+  UDF_LB_ADDR   ParentIcbLocation;\r
+  UINT16        Flags;\r
+} UDF_ICB_TAG;\r
+\r
+typedef struct {\r
+  UDF_DESCRIPTOR_TAG              DescriptorTag;\r
+  UDF_ICB_TAG                     IcbTag;\r
+  UINT32                          Uid;\r
+  UINT32                          Gid;\r
+  UINT32                          Permissions;\r
+  UINT16                          FileLinkCount;\r
+  UINT8                           RecordFormat;\r
+  UINT8                           RecordDisplayAttributes;\r
+  UINT32                          RecordLength;\r
+  UINT64                          InformationLength;\r
+  UINT64                          LogicalBlocksRecorded;\r
+  UDF_TIMESTAMP                   AccessTime;\r
+  UDF_TIMESTAMP                   ModificationTime;\r
+  UDF_TIMESTAMP                   AttributeTime;\r
+  UINT32                          CheckPoint;\r
+  UDF_LONG_ALLOCATION_DESCRIPTOR  ExtendedAttributeIcb;\r
+  UDF_ENTITY_ID                   ImplementationIdentifier;\r
+  UINT64                          UniqueId;\r
+  UINT32                          LengthOfExtendedAttributes;\r
+  UINT32                          LengthOfAllocationDescriptors;\r
+  UINT8                           Data[0]; // L_EA + L_AD\r
+} UDF_FILE_ENTRY;\r
+\r
+typedef struct {\r
+  UDF_DESCRIPTOR_TAG              DescriptorTag;\r
+  UDF_ICB_TAG                     IcbTag;\r
+  UINT32                          Uid;\r
+  UINT32                          Gid;\r
+  UINT32                          Permissions;\r
+  UINT16                          FileLinkCount;\r
+  UINT8                           RecordFormat;\r
+  UINT8                           RecordDisplayAttributes;\r
+  UINT32                          RecordLength;\r
+  UINT64                          InformationLength;\r
+  UINT64                          ObjectSize;\r
+  UINT64                          LogicalBlocksRecorded;\r
+  UDF_TIMESTAMP                   AccessTime;\r
+  UDF_TIMESTAMP                   ModificationTime;\r
+  UDF_TIMESTAMP                   CreationTime;\r
+  UDF_TIMESTAMP                   AttributeTime;\r
+  UINT32                          CheckPoint;\r
+  UINT32                          Reserved;\r
+  UDF_LONG_ALLOCATION_DESCRIPTOR  ExtendedAttributeIcb;\r
+  UDF_LONG_ALLOCATION_DESCRIPTOR  StreamDirectoryIcb;\r
+  UDF_ENTITY_ID                   ImplementationIdentifier;\r
+  UINT64                          UniqueId;\r
+  UINT32                          LengthOfExtendedAttributes;\r
+  UINT32                          LengthOfAllocationDescriptors;\r
+  UINT8                           Data[0]; // L_EA + L_AD\r
+} UDF_EXTENDED_FILE_ENTRY;\r
+\r
+typedef struct {\r
+  UINT8                ComponentType;\r
+  UINT8                LengthOfComponentIdentifier;\r
+  UINT16               ComponentFileVersionNumber;\r
+  UINT8                ComponentIdentifier[0];\r
+} UDF_PATH_COMPONENT;\r
+\r
+#pragma pack()\r
+\r
+//\r
+// UDF filesystem driver's private data\r
+//\r
+typedef struct {\r
+  UDF_LOGICAL_VOLUME_DESCRIPTOR  **LogicalVolDescs;\r
+  UINTN                          LogicalVolDescsNo;\r
+  UDF_PARTITION_DESCRIPTOR       **PartitionDescs;\r
+  UINTN                          PartitionDescsNo;\r
+  UDF_FILE_SET_DESCRIPTOR        **FileSetDescs;\r
+  UINTN                          FileSetDescsNo;\r
+  UINTN                          FileEntrySize;\r
+} UDF_VOLUME_INFO;\r
+\r
+typedef struct {\r
+  VOID                            *FileEntry;\r
+  UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc;\r
+} UDF_FILE_INFO;\r
+\r
+typedef struct {\r
+  VOID                      *DirectoryData;\r
+  UINT64                    DirectoryLength;\r
+  UINT64                    FidOffset;\r
+} UDF_READ_DIRECTORY_INFO;\r
+\r
+#define PRIVATE_UDF_FILE_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'f', 'f')\r
+\r
+#define PRIVATE_UDF_FILE_DATA_FROM_THIS(a) \\r
+  CR ( \\r
+      a, \\r
+      PRIVATE_UDF_FILE_DATA, \\r
+      FileIo, \\r
+      PRIVATE_UDF_FILE_DATA_SIGNATURE \\r
+      )\r
+\r
+typedef struct {\r
+  UINTN                            Signature;\r
+  BOOLEAN                          IsRootDirectory;\r
+  UDF_FILE_INFO                    *Root;\r
+  UDF_FILE_INFO                    File;\r
+  UDF_READ_DIRECTORY_INFO          ReadDirInfo;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *SimpleFs;\r
+  EFI_FILE_PROTOCOL                FileIo;\r
+  CHAR16                           AbsoluteFileName[UDF_PATH_LENGTH];\r
+  CHAR16                           FileName[UDF_FILENAME_LENGTH];\r
+  UINT64                           FileSize;\r
+  UINT64                           FilePosition;\r
+} PRIVATE_UDF_FILE_DATA;\r
+\r
+#define PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'f', 's')\r
+\r
+#define PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS(a) \\r
+  CR ( \\r
+      a, \\r
+      PRIVATE_UDF_SIMPLE_FS_DATA, \\r
+      SimpleFs, \\r
+      PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE \\r
+      )\r
+\r
+typedef struct {\r
+  UINTN                            Signature;\r
+  EFI_BLOCK_IO_PROTOCOL            *BlockIo;\r
+  EFI_DISK_IO_PROTOCOL             *DiskIo;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  SimpleFs;\r
+  UDF_VOLUME_INFO                  Volume;\r
+  UDF_FILE_INFO                    Root;\r
+  UINTN                            OpenFiles;\r
+  EFI_HANDLE                       Handle;\r
+} PRIVATE_UDF_SIMPLE_FS_DATA;\r
+\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL   gUdfDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL   gUdfComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL  gUdfComponentName2;\r
+\r
+//\r
+// Function Prototypes\r
+//\r
+\r
+/**\r
+  Open the root directory on a volume.\r
+\r
+  @param  This Protocol instance pointer.\r
+  @param  Root Returns an Open file handle for the root directory\r
+\r
+  @retval EFI_SUCCESS          The device was opened.\r
+  @retval EFI_UNSUPPORTED      This volume does not support the file system.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.\r
+  @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfOpenVolume (\r
+  IN   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,\r
+  OUT  EFI_FILE_PROTOCOL                **Root\r
+  );\r
+\r
+/**\r
+  Opens a new file relative to the source file's location.\r
+\r
+  @param  This       The protocol instance pointer.\r
+  @param  NewHandle  Returns File Handle for FileName.\r
+  @param  FileName   Null terminated string. "\", ".", and ".." are supported.\r
+  @param  OpenMode   Open mode for file.\r
+  @param  Attributes Only used for EFI_FILE_MODE_CREATE.\r
+\r
+  @retval EFI_SUCCESS          The device was opened.\r
+  @retval EFI_NOT_FOUND        The specified file could not be found on the device.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_MEDIA_CHANGED    The media has changed.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.\r
+  @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.\r
+  @retval EFI_VOLUME_FULL      The volume is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfOpen (\r
+  IN   EFI_FILE_PROTOCOL  *This,\r
+  OUT  EFI_FILE_PROTOCOL  **NewHandle,\r
+  IN   CHAR16             *FileName,\r
+  IN   UINT64             OpenMode,\r
+  IN   UINT64             Attributes\r
+  );\r
+\r
+/**\r
+  Read data from the file.\r
+\r
+  @param  This       Protocol instance pointer.\r
+  @param  BufferSize On input size of buffer, on output amount of data in buffer.\r
+  @param  Buffer     The buffer in which data is read.\r
+\r
+  @retval EFI_SUCCESS          Data was read.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_BUFFER_TO_SMALL  BufferSize is too small. BufferSize contains required size.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfRead (\r
+  IN      EFI_FILE_PROTOCOL  *This,\r
+  IN OUT  UINTN              *BufferSize,\r
+  OUT     VOID               *Buffer\r
+  );\r
+\r
+/**\r
+  Close the file handle.\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS The file was closed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfClose (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  );\r
+\r
+/**\r
+  Close and delete the file handle.\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS              The file was closed and deleted.\r
+  @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not\r
+                                   deleted.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfDelete (\r
+  IN EFI_FILE_PROTOCOL  *This\r
+  );\r
+\r
+/**\r
+  Write data to a file.\r
+\r
+  @param  This       Protocol instance pointer.\r
+  @param  BufferSize On input size of buffer, on output amount of data in buffer.\r
+  @param  Buffer     The buffer in which data to write.\r
+\r
+  @retval EFI_SUCCESS          Data was written.\r
+  @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED  The device is write protected.\r
+  @retval EFI_ACCESS_DENIED    The file was open for read only.\r
+  @retval EFI_VOLUME_FULL      The volume is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfWrite (\r
+  IN      EFI_FILE_PROTOCOL  *This,\r
+  IN OUT  UINTN              *BufferSize,\r
+  IN      VOID               *Buffer\r
+  );\r
+\r
+/**\r
+  Get file's current position.\r
+\r
+  @param  This      Protocol instance pointer.\r
+  @param  Position  Byte position from the start of the file.\r
+\r
+  @retval EFI_SUCCESS     Position was updated.\r
+  @retval EFI_UNSUPPORTED Seek request for directories is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfGetPosition (\r
+  IN   EFI_FILE_PROTOCOL  *This,\r
+  OUT  UINT64             *Position\r
+  );\r
+\r
+/**\r
+  Set file's current position.\r
+\r
+  @param  This      Protocol instance pointer.\r
+  @param  Position  Byte position from the start of the file.\r
+\r
+  @retval EFI_SUCCESS      Position was updated.\r
+  @retval EFI_UNSUPPORTED  Seek request for non-zero is not valid on open.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfSetPosition (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN UINT64             Position\r
+  );\r
+\r
+/**\r
+  Get information about a file.\r
+\r
+  @param  This            Protocol instance pointer.\r
+  @param  InformationType Type of information to return in Buffer.\r
+  @param  BufferSize      On input size of buffer, on output amount of data in buffer.\r
+  @param  Buffer          The buffer to return data.\r
+\r
+  @retval EFI_SUCCESS          Data was returned.\r
+  @retval EFI_UNSUPPORTED      InformationType is not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED  The device is write protected.\r
+  @retval EFI_ACCESS_DENIED    The file was open for read only.\r
+  @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfGetInfo (\r
+  IN      EFI_FILE_PROTOCOL  *This,\r
+  IN      EFI_GUID           *InformationType,\r
+  IN OUT  UINTN              *BufferSize,\r
+  OUT     VOID               *Buffer\r
+  );\r
+\r
+/**\r
+  Set information about a file.\r
+\r
+  @param  File            Protocol instance pointer.\r
+  @param  InformationType Type of information in Buffer.\r
+  @param  BufferSize      Size of buffer.\r
+  @param  Buffer          The data to write.\r
+\r
+  @retval EFI_SUCCESS          Data was set.\r
+  @retval EFI_UNSUPPORTED      InformationType is not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED  The device is write protected.\r
+  @retval EFI_ACCESS_DENIED    The file was open for read only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfSetInfo (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  IN EFI_GUID           *InformationType,\r
+  IN UINTN              BufferSize,\r
+  IN VOID               *Buffer\r
+  );\r
+\r
+/**\r
+  Flush data back for the file handle.\r
+\r
+  @param  This Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS          Data was flushed.\r
+  @retval EFI_UNSUPPORTED      Writes to Open directory are not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED  The device is write protected.\r
+  @retval EFI_ACCESS_DENIED    The file was open for read only.\r
+  @retval EFI_VOLUME_FULL      The volume is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfFlush (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  );\r
+\r
+/**\r
+  Read volume information on a medium which contains a valid UDF file system.\r
+\r
+  @param[in]   BlockIo  BlockIo interface.\r
+  @param[in]   DiskIo   DiskIo interface.\r
+  @param[out]  Volume   UDF volume information structure.\r
+\r
+  @retval EFI_SUCCESS          Volume information read.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadUdfVolumeInformation (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  OUT  UDF_VOLUME_INFO        *Volume\r
+  );\r
+\r
+/**\r
+  Find the root directory on an UDF volume.\r
+\r
+  @param[in]   BlockIo  BlockIo interface.\r
+  @param[in]   DiskIo   DiskIo interface.\r
+  @param[in]   Volume   UDF volume information structure.\r
+  @param[out]  File     Root directory file.\r
+\r
+  @retval EFI_SUCCESS          Root directory found.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+FindRootDirectory (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN   UDF_VOLUME_INFO        *Volume,\r
+  OUT  UDF_FILE_INFO          *File\r
+  );\r
+\r
+/**\r
+  Find either a File Entry or a Extended File Entry from a given ICB.\r
+\r
+  @param[in]   BlockIo    BlockIo interface.\r
+  @param[in]   DiskIo     DiskIo interface.\r
+  @param[in]   Volume     UDF volume information structure.\r
+  @param[in]   Icb        ICB of the FID.\r
+  @param[out]  FileEntry  File Entry or Extended File Entry.\r
+\r
+  @retval EFI_SUCCESS          File Entry or Extended File Entry found.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+FindFileEntry (\r
+  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN   UDF_VOLUME_INFO                 *Volume,\r
+  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *Icb,\r
+  OUT  VOID                            **FileEntry\r
+  );\r
+\r
+/**\r
+  Find a file given its absolute path on an UDF volume.\r
+\r
+  @param[in]   BlockIo   BlockIo interface.\r
+  @param[in]   DiskIo    DiskIo interface.\r
+  @param[in]   Volume    UDF volume information structure.\r
+  @param[in]   FilePath  File's absolute path.\r
+  @param[in]   Root      Root directory file.\r
+  @param[in]   Parent    Parent directory file.\r
+  @param[out]  File      Found file.\r
+\r
+  @retval EFI_SUCCESS          @p FilePath was found.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The @p FilePath file was not found due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+FindFile (\r
+  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN   UDF_VOLUME_INFO                 *Volume,\r
+  IN   CHAR16                          *FilePath,\r
+  IN   UDF_FILE_INFO                   *Root,\r
+  IN   UDF_FILE_INFO                   *Parent,\r
+  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *Icb,\r
+  OUT  UDF_FILE_INFO                   *File\r
+  );\r
+\r
+/**\r
+  Read a directory entry at a time on an UDF volume.\r
+\r
+  @param[in]      BlockIo        BlockIo interface.\r
+  @param[in]      DiskIo         DiskIo interface.\r
+  @param[in]      Volume         UDF volume information structure.\r
+  @param[in]      ParentIcb      ICB of the parent file.\r
+  @param[in]      FileEntryData  FE/EFE of the parent file.\r
+  @param[in out]  ReadDirInfo    Next read directory listing structure\r
+                                 information.\r
+  @param[out]     FoundFid       File Identifier Descriptor pointer.\r
+\r
+  @retval EFI_SUCCESS          Directory entry read.\r
+  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadDirectoryEntry (\r
+  IN      EFI_BLOCK_IO_PROTOCOL           *BlockIo,\r
+  IN      EFI_DISK_IO_PROTOCOL            *DiskIo,\r
+  IN      UDF_VOLUME_INFO                 *Volume,\r
+  IN      UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,\r
+  IN      VOID                            *FileEntryData,\r
+  IN OUT  UDF_READ_DIRECTORY_INFO         *ReadDirInfo,\r
+  OUT     UDF_FILE_IDENTIFIER_DESCRIPTOR  **FoundFid\r
+  );\r
+\r
+/**\r
+  Get a filename (encoded in OSTA-compressed format) from a File Identifier\r
+  Descriptor on an UDF volume.\r
+\r
+  @param[in]   FileIdentifierDesc  File Identifier Descriptor pointer.\r
+  @param[out]  FileName            Decoded filename.\r
+\r
+  @retval EFI_SUCCESS           Filename decoded and read.\r
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
+**/\r
+EFI_STATUS\r
+GetFileNameFromFid (\r
+  IN   UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc,\r
+  OUT  CHAR16                          *FileName\r
+  );\r
+\r
+/**\r
+  Resolve a symlink file on an UDF volume.\r
+\r
+  @param[in]   BlockIo        BlockIo interface.\r
+  @param[in]   DiskIo         DiskIo interface.\r
+  @param[in]   Volume         UDF volume information structure.\r
+  @param[in]   Parent         Parent file.\r
+  @param[in]   FileEntryData  FE/EFE structure pointer.\r
+  @param[out]  File           Resolved file.\r
+\r
+  @retval EFI_SUCCESS          Symlink file resolved.\r
+  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+ResolveSymlink (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN   UDF_VOLUME_INFO        *Volume,\r
+  IN   UDF_FILE_INFO          *Parent,\r
+  IN   VOID                   *FileEntryData,\r
+  OUT  UDF_FILE_INFO          *File\r
+  );\r
+\r
+/**\r
+  Clean up in-memory UDF volume information.\r
+\r
+  @param[in] Volume Volume information pointer.\r
+\r
+**/\r
+VOID\r
+CleanupVolumeInformation (\r
+  IN UDF_VOLUME_INFO *Volume\r
+  );\r
+\r
+/**\r
+  Clean up in-memory UDF file information.\r
+\r
+  @param[in] File File information pointer.\r
+\r
+**/\r
+VOID\r
+CleanupFileInformation (\r
+  IN UDF_FILE_INFO *File\r
+  );\r
+\r
+/**\r
+  Find a file from its absolute path on an UDF volume.\r
+\r
+  @param[in]   BlockIo  BlockIo interface.\r
+  @param[in]   DiskIo   DiskIo interface.\r
+  @param[in]   Volume   UDF volume information structure.\r
+  @param[in]   File     File information structure.\r
+  @param[out]  Size     Size of the file.\r
+\r
+  @retval EFI_SUCCESS          File size calculated and set in @p Size.\r
+  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFileSize (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN   UDF_VOLUME_INFO        *Volume,\r
+  IN   UDF_FILE_INFO          *File,\r
+  OUT  UINT64                 *Size\r
+  );\r
+\r
+/**\r
+  Set information about a file on an UDF volume.\r
+\r
+  @param[in]      File        File pointer.\r
+  @param[in]      FileSize    Size of the file.\r
+  @param[in]      FileName    Filename of the file.\r
+  @param[in out]  BufferSize  Size of the returned file infomation.\r
+  @param[out]     Buffer      Data of the returned file information.\r
+\r
+  @retval EFI_SUCCESS          File information set.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of\r
+                               resources.\r
+\r
+**/\r
+EFI_STATUS\r
+SetFileInfo (\r
+  IN      UDF_FILE_INFO  *File,\r
+  IN      UINT64         FileSize,\r
+  IN      CHAR16         *FileName,\r
+  IN OUT  UINTN          *BufferSize,\r
+  OUT     VOID           *Buffer\r
+  );\r
+\r
+/**\r
+  Get volume and free space size information of an UDF volume.\r
+\r
+  @param[in]   BlockIo        BlockIo interface.\r
+  @param[in]   DiskIo         DiskIo interface.\r
+  @param[in]   Volume         UDF volume information structure.\r
+  @param[out]  VolumeSize     Volume size.\r
+  @param[out]  FreeSpaceSize  Free space size.\r
+\r
+  @retval EFI_SUCCESS          Volume and free space size calculated.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The volume and free space size were not\r
+                               calculated due to lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+GetVolumeSize (\r
+  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN   UDF_VOLUME_INFO        *Volume,\r
+  OUT  UINT64                 *VolumeSize,\r
+  OUT  UINT64                 *FreeSpaceSize\r
+  );\r
+\r
+/**\r
+  Seek a file and read its data into memory on an UDF volume.\r
+\r
+  @param[in]      BlockIo       BlockIo interface.\r
+  @param[in]      DiskIo        DiskIo interface.\r
+  @param[in]      Volume        UDF volume information structure.\r
+  @param[in]      File          File information structure.\r
+  @param[in]      FileSize      Size of the file.\r
+  @param[in out]  FilePosition  File position.\r
+  @param[in out]  Buffer        File data.\r
+  @param[in out]  BufferSize    Read size.\r
+\r
+  @retval EFI_SUCCESS          File seeked and read.\r
+  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack\r
+                               of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadFileData (\r
+  IN      EFI_BLOCK_IO_PROTOCOL  *BlockIo,\r
+  IN      EFI_DISK_IO_PROTOCOL   *DiskIo,\r
+  IN      UDF_VOLUME_INFO        *Volume,\r
+  IN      UDF_FILE_INFO          *File,\r
+  IN      UINT64                 FileSize,\r
+  IN OUT  UINT64                 *FilePosition,\r
+  IN OUT  VOID                   *Buffer,\r
+  IN OUT  UINT64                 *BufferSize\r
+  );\r
+\r
+/**\r
+  Check if ControllerHandle supports an UDF file system.\r
+\r
+  @param[in]  This                Protocol instance pointer.\r
+  @param[in]  ControllerHandle    Handle of device to test.\r
+\r
+  @retval EFI_SUCCESS             UDF file system found.\r
+  @retval EFI_UNSUPPORTED         UDF file system not found.\r
+\r
+**/\r
+EFI_STATUS\r
+SupportUdfFileSystem (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle\r
+  );\r
+\r
+/**\r
+  Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..".\r
+\r
+  @param[in] FileName Filename.\r
+\r
+  @retval @p FileName Filename mangled.\r
+\r
+**/\r
+CHAR16 *\r
+MangleFileName (\r
+  IN CHAR16        *FileName\r
+  );\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
+  than contains a BlockIo and DiskIo protocol can be supported.\r
+\r
+  @param  This                Protocol instance pointer.\r
+  @param  ControllerHandle    Handle of device to test\r
+  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
+                              device to start.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device\r
+  @retval EFI_ALREADY_STARTED This driver is already running on this device\r
+  @retval other               This driver does not support this device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Start this driver on ControllerHandle by opening a Block IO and Disk IO\r
+  protocol, reading Device Path, and creating a child handle with a\r
+  Disk IO and device path protocol.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  ControllerHandle     Handle of device to bind driver to\r
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                               device to start.\r
+\r
+  @retval EFI_SUCCESS          This driver is added to ControllerHandle\r
+  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle\r
+  @retval other                This driver does not support this device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stop this driver on ControllerHandle. Support stopping any child handles\r
+  created by this driver.\r
+\r
+  @param  This              Protocol instance pointer.\r
+  @param  ControllerHandle  Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
+  @retval other             This driver was not removed from this device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN  EFI_HANDLE                    ControllerHandle,\r
+  IN  UINTN                         NumberOfChildren,\r
+  IN  EFI_HANDLE                    *ChildHandleBuffer\r
+  );\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UdfComponentNameGetControllerName (\r
+  IN   EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN   EFI_HANDLE                   ControllerHandle,\r
+  IN   EFI_HANDLE                   ChildHandle OPTIONAL,\r
+  IN   CHAR8                        *Language,\r
+  OUT  CHAR16                       **ControllerName\r
+  );\r
+\r
+#endif // _UDF_H_\r
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf b/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
new file mode 100644 (file)
index 0000000..7fea6bd
--- /dev/null
@@ -0,0 +1,66 @@
+## @file\r
+#  UDF/ECMA-167 file system driver.\r
+#\r
+#  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UdfDxe\r
+  FILE_GUID                      = 905f13b0-8f91-4b0a-bd76-e1e78f9422e4\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializeUdf\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                = gUdfDriverBinding\r
+#  COMPONENT_NAME                = gUdfComponentName\r
+#  COMPONENT_NAME2               = gUdfComponentName2\r
+#\r
+\r
+[Sources]\r
+  ComponentName.c\r
+  FileSystemOperations.c\r
+  FileName.c\r
+  File.c\r
+  Udf.c\r
+  Udf.h\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  DevicePathLib\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  UefiLib\r
+  BaseLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+\r
+\r
+[Guids]\r
+  gEfiFileInfoGuid                              ## SOMETIMES_CONSUMES ## Protocol\r
+  gEfiFileSystemInfoGuid                        ## SOMETIMES_CONSUMES ## Protocol\r
+\r
+\r
+[Protocols]\r
+  gEfiSimpleFileSystemProtocolGuid              ## BY_START\r
+  gEfiDevicePathProtocolGuid                    ## BY_START\r
+  gEfiBlockIoProtocolGuid                       ## TO_START\r
+  gEfiDiskIoProtocolGuid                        ## TO_START\r