--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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