mirror of https://github.com/acidanthera/audk.git
MdeModulePkg: Initial UDF/ECMA-167 file system support
This patch introduces UDF file system support in EDK2. All block devices that support BlockIo and DiskIo protocols and contain a valid UDF file system - as specified by OSTA Universal Disk Format (revisions 1.02 through 2.60) - will be installed EFI_SIMPLE_FILE_SYSTEM_PROTOCOL to provide access to underlying file system. File system operations on regular, directory and symlink files are supported. Cc: Star Zeng <star.zeng@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
This commit is contained in:
parent
8aafec2c13
commit
99c9b94905
|
@ -0,0 +1,185 @@
|
|||
/** @file
|
||||
UEFI Component Name protocol for UDF/ECMA-167 file system driver.
|
||||
|
||||
Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
|
||||
|
||||
This program and the accompanying materials are licensed and made available
|
||||
under the terms and conditions of the BSD License which accompanies this
|
||||
distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include "Udf.h"
|
||||
|
||||
//
|
||||
// EFI Component Name Protocol
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUdfComponentName = {
|
||||
UdfComponentNameGetDriverName,
|
||||
UdfComponentNameGetControllerName,
|
||||
"eng"
|
||||
};
|
||||
|
||||
//
|
||||
// EFI Component Name 2 Protocol
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUdfComponentName2 = {
|
||||
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UdfComponentNameGetDriverName,
|
||||
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UdfComponentNameGetControllerName,
|
||||
"en"
|
||||
};
|
||||
|
||||
//
|
||||
// Driver name table for Udf module.
|
||||
// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUdfDriverNameTable[] = {
|
||||
{
|
||||
"eng;en",
|
||||
L"UDF File System Driver"
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the driver.
|
||||
|
||||
This function retrieves the user readable name of a driver in the form of a
|
||||
Unicode string. If the driver specified by This has a user readable name in
|
||||
the language specified by Language, then a pointer to the driver name is
|
||||
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
|
||||
by This does not support the language specified by Language,
|
||||
then EFI_UNSUPPORTED is returned.
|
||||
|
||||
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
|
||||
EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
|
||||
@param Language[in] A pointer to a Null-terminated ASCII string
|
||||
array indicating the language. This is the
|
||||
language of the driver name that the caller is
|
||||
requesting, and it must match one of the
|
||||
languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up
|
||||
to the driver writer. Language is specified
|
||||
in RFC 4646 or ISO 639-2 language code format.
|
||||
|
||||
@param DriverName[out] A pointer to the Unicode string to return.
|
||||
This Unicode string is the name of the
|
||||
driver specified by This in the language
|
||||
specified by Language.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the Driver specified by
|
||||
This and the language specified by Language was
|
||||
returned in DriverName.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER DriverName is NULL.
|
||||
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support
|
||||
the language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
)
|
||||
{
|
||||
return LookupUnicodeString2 (
|
||||
Language,
|
||||
This->SupportedLanguages,
|
||||
mUdfDriverNameTable,
|
||||
DriverName,
|
||||
(BOOLEAN)(This == &gUdfComponentName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the controller
|
||||
that is being managed by a driver.
|
||||
|
||||
This function retrieves the user readable name of the controller specified by
|
||||
ControllerHandle and ChildHandle in the form of a Unicode string. If the
|
||||
driver specified by This has a user readable name in the language specified by
|
||||
Language, then a pointer to the controller name is returned in ControllerName,
|
||||
and EFI_SUCCESS is returned. If the driver specified by This is not currently
|
||||
managing the controller specified by ControllerHandle and ChildHandle,
|
||||
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
|
||||
support the language specified by Language, then EFI_UNSUPPORTED is returned.
|
||||
|
||||
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
|
||||
EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
|
||||
@param ControllerHandle[in] The handle of a controller that the driver
|
||||
specified by This is managing. This handle
|
||||
specifies the controller whose name is to be
|
||||
returned.
|
||||
|
||||
@param ChildHandle[in] The handle of the child controller to retrieve
|
||||
the name of. This is an optional parameter that
|
||||
may be NULL. It will be NULL for device
|
||||
drivers. It will also be NULL for a bus drivers
|
||||
that wish to retrieve the name of the bus
|
||||
controller. It will not be NULL for a bus
|
||||
driver that wishes to retrieve the name of a
|
||||
child controller.
|
||||
|
||||
@param Language[in] A pointer to a Null-terminated ASCII string
|
||||
array indicating the language. This is the
|
||||
language of the driver name that the caller is
|
||||
requesting, and it must match one of the
|
||||
languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up
|
||||
to the driver writer. Language is specified in
|
||||
RFC 4646 or ISO 639-2 language code format.
|
||||
|
||||
@param ControllerName[out] A pointer to the Unicode string to return.
|
||||
This Unicode string is the name of the
|
||||
controller specified by ControllerHandle and
|
||||
ChildHandle in the language specified by
|
||||
Language from the point of view of the driver
|
||||
specified by This.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the user readable name in
|
||||
the language specified by Language for the
|
||||
driver specified by This was returned in
|
||||
DriverName.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
|
||||
EFI_HANDLE.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
|
||||
|
||||
@retval EFI_UNSUPPORTED The driver specified by This is not currently
|
||||
managing the controller specified by
|
||||
ControllerHandle and ChildHandle.
|
||||
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support
|
||||
the language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfComponentNameGetControllerName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
|
@ -0,0 +1,908 @@
|
|||
/** @file
|
||||
Handle operations in files and directories from UDF/ECMA-167 file systems.
|
||||
|
||||
Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
|
||||
|
||||
This program and the accompanying materials are licensed and made available
|
||||
under the terms and conditions of the BSD License which accompanies this
|
||||
distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include "Udf.h"
|
||||
|
||||
EFI_FILE_PROTOCOL gUdfFileIoOps = {
|
||||
EFI_FILE_PROTOCOL_REVISION,
|
||||
UdfOpen,
|
||||
UdfClose,
|
||||
UdfDelete,
|
||||
UdfRead,
|
||||
UdfWrite,
|
||||
UdfGetPosition,
|
||||
UdfSetPosition,
|
||||
UdfGetInfo,
|
||||
UdfSetInfo,
|
||||
UdfFlush,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define _ROOT_FILE(_PrivData) (_PrivData)->Root
|
||||
#define _PARENT_FILE(_PrivData) \
|
||||
((_PrivData)->IsRootDirectory ? (_PrivData)->Root : &(_PrivData)->File)
|
||||
#define _FILE(_PrivData) _PARENT_FILE(_PrivData)
|
||||
|
||||
/**
|
||||
Open the root directory on a volume.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param Root Returns an Open file handle for the root directory
|
||||
|
||||
@retval EFI_SUCCESS The device was opened.
|
||||
@retval EFI_UNSUPPORTED This volume does not support the file system.
|
||||
@retval EFI_NO_MEDIA The device has no media.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error.
|
||||
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
|
||||
@retval EFI_ACCESS_DENIED The service denied access to the file.
|
||||
@retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
|
||||
resources.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfOpenVolume (
|
||||
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
|
||||
OUT EFI_FILE_PROTOCOL **Root
|
||||
)
|
||||
{
|
||||
EFI_TPL OldTpl;
|
||||
EFI_STATUS Status;
|
||||
PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
|
||||
PRIVATE_UDF_FILE_DATA *PrivFileData;
|
||||
|
||||
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
||||
|
||||
if (This == NULL || Root == NULL) {
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto Error_Invalid_Params;
|
||||
}
|
||||
|
||||
PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This);
|
||||
|
||||
if (PrivFsData->OpenFiles == 0) {
|
||||
//
|
||||
// There is no more open files. Read volume information again since it was
|
||||
// cleaned up on the last UdfClose() call.
|
||||
//
|
||||
Status = ReadUdfVolumeInformation (
|
||||
PrivFsData->BlockIo,
|
||||
PrivFsData->DiskIo,
|
||||
&PrivFsData->Volume
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error_Read_Udf_Volume;
|
||||
}
|
||||
}
|
||||
|
||||
CleanupFileInformation (&PrivFsData->Root);
|
||||
|
||||
//
|
||||
// Find root directory file.
|
||||
//
|
||||
Status = FindRootDirectory (
|
||||
PrivFsData->BlockIo,
|
||||
PrivFsData->DiskIo,
|
||||
&PrivFsData->Volume,
|
||||
&PrivFsData->Root
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error_Find_Root_Dir;
|
||||
}
|
||||
|
||||
PrivFileData =
|
||||
(PRIVATE_UDF_FILE_DATA *) AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
|
||||
if (PrivFileData == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Error_Alloc_Priv_File_Data;
|
||||
}
|
||||
|
||||
PrivFileData->Signature = PRIVATE_UDF_FILE_DATA_SIGNATURE;
|
||||
PrivFileData->SimpleFs = This;
|
||||
PrivFileData->Root = &PrivFsData->Root;
|
||||
PrivFileData->IsRootDirectory = TRUE;
|
||||
|
||||
CopyMem ((VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps,
|
||||
sizeof (EFI_FILE_PROTOCOL));
|
||||
|
||||
*Root = &PrivFileData->FileIo;
|
||||
|
||||
PrivFsData->OpenFiles++;
|
||||
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
Error_Alloc_Priv_File_Data:
|
||||
CleanupFileInformation (&PrivFsData->Root);
|
||||
|
||||
Error_Find_Root_Dir:
|
||||
CleanupVolumeInformation (&PrivFsData->Volume);
|
||||
|
||||
Error_Read_Udf_Volume:
|
||||
Error_Invalid_Params:
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Opens a new file relative to the source file's location.
|
||||
|
||||
@param This The protocol instance pointer.
|
||||
@param NewHandle Returns File Handle for FileName.
|
||||
@param FileName Null terminated string. "\", ".", and ".." are supported.
|
||||
@param OpenMode Open mode for file.
|
||||
@param Attributes Only used for EFI_FILE_MODE_CREATE.
|
||||
|
||||
@retval EFI_SUCCESS The device was opened.
|
||||
@retval EFI_NOT_FOUND The specified file could not be found on the
|
||||
device.
|
||||
@retval EFI_NO_MEDIA The device has no media.
|
||||
@retval EFI_MEDIA_CHANGED The media has changed.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error.
|
||||
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
|
||||
@retval EFI_ACCESS_DENIED The service denied access to the file.
|
||||
@retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
|
||||
resources.
|
||||
@retval EFI_VOLUME_FULL The volume is full.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfOpen (
|
||||
IN EFI_FILE_PROTOCOL *This,
|
||||
OUT EFI_FILE_PROTOCOL **NewHandle,
|
||||
IN CHAR16 *FileName,
|
||||
IN UINT64 OpenMode,
|
||||
IN UINT64 Attributes
|
||||
)
|
||||
{
|
||||
EFI_TPL OldTpl;
|
||||
EFI_STATUS Status;
|
||||
PRIVATE_UDF_FILE_DATA *PrivFileData;
|
||||
PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
|
||||
CHAR16 FilePath[UDF_PATH_LENGTH] = { 0 };
|
||||
UDF_FILE_INFO File;
|
||||
PRIVATE_UDF_FILE_DATA *NewPrivFileData;
|
||||
CHAR16 *TempFileName;
|
||||
|
||||
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
||||
|
||||
if (This == NULL || NewHandle == NULL || FileName == NULL) {
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto Error_Invalid_Params;
|
||||
}
|
||||
|
||||
if (OpenMode != EFI_FILE_MODE_READ) {
|
||||
Status = EFI_WRITE_PROTECTED;
|
||||
goto Error_Invalid_Params;
|
||||
}
|
||||
|
||||
PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
|
||||
|
||||
PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
|
||||
|
||||
//
|
||||
// Build full path
|
||||
//
|
||||
if (*FileName == L'\\') {
|
||||
StrCpyS (FilePath, UDF_PATH_LENGTH, FileName);
|
||||
} else {
|
||||
StrCpyS (FilePath, UDF_PATH_LENGTH, PrivFileData->AbsoluteFileName);
|
||||
StrCatS (FilePath, UDF_PATH_LENGTH, L"\\");
|
||||
StrCatS (FilePath, UDF_PATH_LENGTH, FileName);
|
||||
}
|
||||
|
||||
MangleFileName (FilePath);
|
||||
if (FilePath[0] == L'\0') {
|
||||
Status = EFI_NOT_FOUND;
|
||||
goto Error_Bad_FileName;
|
||||
}
|
||||
|
||||
Status = FindFile (
|
||||
PrivFsData->BlockIo,
|
||||
PrivFsData->DiskIo,
|
||||
&PrivFsData->Volume,
|
||||
FilePath,
|
||||
_ROOT_FILE (PrivFileData),
|
||||
_PARENT_FILE (PrivFileData),
|
||||
&_PARENT_FILE(PrivFileData)->FileIdentifierDesc->Icb,
|
||||
&File
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error_Find_File;
|
||||
}
|
||||
|
||||
NewPrivFileData =
|
||||
(PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
|
||||
if (NewPrivFileData == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Error_Alloc_New_Priv_File_Data;
|
||||
}
|
||||
|
||||
CopyMem ((VOID *)NewPrivFileData, (VOID *)PrivFileData,
|
||||
sizeof (PRIVATE_UDF_FILE_DATA));
|
||||
CopyMem ((VOID *)&NewPrivFileData->File, &File, sizeof (UDF_FILE_INFO));
|
||||
|
||||
NewPrivFileData->IsRootDirectory = FALSE;
|
||||
|
||||
StrCpyS (NewPrivFileData->AbsoluteFileName, UDF_PATH_LENGTH, FilePath);
|
||||
FileName = NewPrivFileData->AbsoluteFileName;
|
||||
|
||||
while ((TempFileName = StrStr (FileName, L"\\")) != NULL) {
|
||||
FileName = TempFileName + 1;
|
||||
}
|
||||
|
||||
StrCpyS (NewPrivFileData->FileName, UDF_PATH_LENGTH, FileName);
|
||||
|
||||
Status = GetFileSize (
|
||||
PrivFsData->BlockIo,
|
||||
PrivFsData->DiskIo,
|
||||
&PrivFsData->Volume,
|
||||
&NewPrivFileData->File,
|
||||
&NewPrivFileData->FileSize
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error_Get_File_Size;
|
||||
}
|
||||
|
||||
NewPrivFileData->FilePosition = 0;
|
||||
ZeroMem ((VOID *)&NewPrivFileData->ReadDirInfo,
|
||||
sizeof (UDF_READ_DIRECTORY_INFO));
|
||||
|
||||
*NewHandle = &NewPrivFileData->FileIo;
|
||||
|
||||
PrivFsData->OpenFiles++;
|
||||
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
|
||||
return Status;
|
||||
|
||||
Error_Get_File_Size:
|
||||
FreePool ((VOID *)NewPrivFileData);
|
||||
|
||||
Error_Alloc_New_Priv_File_Data:
|
||||
CleanupFileInformation (&File);
|
||||
|
||||
Error_Find_File:
|
||||
Error_Bad_FileName:
|
||||
Error_Invalid_Params:
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Read data from the file.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param BufferSize On input size of buffer, on output amount of data in
|
||||
buffer.
|
||||
@param Buffer The buffer in which data is read.
|
||||
|
||||
@retval EFI_SUCCESS Data was read.
|
||||
@retval EFI_NO_MEDIA The device has no media.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error.
|
||||
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
|
||||
@retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains
|
||||
required size.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfRead (
|
||||
IN EFI_FILE_PROTOCOL *This,
|
||||
IN OUT UINTN *BufferSize,
|
||||
OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_TPL OldTpl;
|
||||
EFI_STATUS Status;
|
||||
PRIVATE_UDF_FILE_DATA *PrivFileData;
|
||||
PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
|
||||
UDF_VOLUME_INFO *Volume;
|
||||
UDF_FILE_INFO *Parent;
|
||||
UDF_READ_DIRECTORY_INFO *ReadDirInfo;
|
||||
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
||||
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||||
UDF_FILE_INFO FoundFile;
|
||||
UDF_FILE_IDENTIFIER_DESCRIPTOR *NewFileIdentifierDesc;
|
||||
VOID *NewFileEntryData;
|
||||
CHAR16 FileName[UDF_FILENAME_LENGTH] = { 0 };
|
||||
UINT64 FileSize;
|
||||
UINT64 BufferSizeUint64;
|
||||
|
||||
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
||||
|
||||
if (This == NULL || BufferSize == NULL || (*BufferSize != 0 &&
|
||||
Buffer == NULL)) {
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto Error_Invalid_Params;
|
||||
}
|
||||
|
||||
PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
|
||||
PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
|
||||
|
||||
BlockIo = PrivFsData->BlockIo;
|
||||
DiskIo = PrivFsData->DiskIo;
|
||||
Volume = &PrivFsData->Volume;
|
||||
ReadDirInfo = &PrivFileData->ReadDirInfo;
|
||||
NewFileIdentifierDesc = NULL;
|
||||
NewFileEntryData = NULL;
|
||||
|
||||
Parent = _PARENT_FILE (PrivFileData);
|
||||
|
||||
Status = EFI_VOLUME_CORRUPTED;
|
||||
|
||||
if (IS_FID_NORMAL_FILE (Parent->FileIdentifierDesc)) {
|
||||
if (PrivFileData->FilePosition > PrivFileData->FileSize) {
|
||||
//
|
||||
// File's position is beyond the EOF
|
||||
//
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
goto Error_File_Beyond_The_Eof;
|
||||
}
|
||||
|
||||
if (PrivFileData->FilePosition == PrivFileData->FileSize) {
|
||||
*BufferSize = 0;
|
||||
Status = EFI_SUCCESS;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
BufferSizeUint64 = *BufferSize;
|
||||
|
||||
Status = ReadFileData (
|
||||
BlockIo,
|
||||
DiskIo,
|
||||
Volume,
|
||||
Parent,
|
||||
PrivFileData->FileSize,
|
||||
&PrivFileData->FilePosition,
|
||||
Buffer,
|
||||
&BufferSizeUint64
|
||||
);
|
||||
ASSERT (BufferSizeUint64 <= MAX_UINTN);
|
||||
*BufferSize = (UINTN)BufferSizeUint64;
|
||||
} else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) {
|
||||
if (ReadDirInfo->FidOffset == 0 && PrivFileData->FilePosition > 0) {
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
*BufferSize = 0;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
Status = ReadDirectoryEntry (
|
||||
BlockIo,
|
||||
DiskIo,
|
||||
Volume,
|
||||
&Parent->FileIdentifierDesc->Icb,
|
||||
Parent->FileEntry,
|
||||
ReadDirInfo,
|
||||
&NewFileIdentifierDesc
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
if (Status == EFI_DEVICE_ERROR) {
|
||||
FreePool (ReadDirInfo->DirectoryData);
|
||||
ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
|
||||
|
||||
*BufferSize = 0;
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) {
|
||||
break;
|
||||
}
|
||||
|
||||
FreePool ((VOID *)NewFileIdentifierDesc);
|
||||
}
|
||||
|
||||
Status = FindFileEntry (
|
||||
BlockIo,
|
||||
DiskIo,
|
||||
Volume,
|
||||
&NewFileIdentifierDesc->Icb,
|
||||
&NewFileEntryData
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error_Find_Fe;
|
||||
}
|
||||
|
||||
if (IS_FE_SYMLINK (NewFileEntryData)) {
|
||||
Status = ResolveSymlink (
|
||||
BlockIo,
|
||||
DiskIo,
|
||||
Volume,
|
||||
Parent,
|
||||
NewFileEntryData,
|
||||
&FoundFile
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error_Resolve_Symlink;
|
||||
}
|
||||
|
||||
FreePool ((VOID *)NewFileEntryData);
|
||||
NewFileEntryData = FoundFile.FileEntry;
|
||||
|
||||
Status = GetFileNameFromFid (NewFileIdentifierDesc, FileName);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool ((VOID *)FoundFile.FileIdentifierDesc);
|
||||
goto Error_Get_FileName;
|
||||
}
|
||||
|
||||
FreePool ((VOID *)NewFileIdentifierDesc);
|
||||
NewFileIdentifierDesc = FoundFile.FileIdentifierDesc;
|
||||
} else {
|
||||
FoundFile.FileIdentifierDesc = NewFileIdentifierDesc;
|
||||
FoundFile.FileEntry = NewFileEntryData;
|
||||
|
||||
Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, FileName);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error_Get_FileName;
|
||||
}
|
||||
}
|
||||
|
||||
Status = GetFileSize (
|
||||
BlockIo,
|
||||
DiskIo,
|
||||
Volume,
|
||||
&FoundFile,
|
||||
&FileSize
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error_Get_File_Size;
|
||||
}
|
||||
|
||||
Status = SetFileInfo (
|
||||
&FoundFile,
|
||||
FileSize,
|
||||
FileName,
|
||||
BufferSize,
|
||||
Buffer
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error_Set_File_Info;
|
||||
}
|
||||
|
||||
PrivFileData->FilePosition++;
|
||||
Status = EFI_SUCCESS;
|
||||
} else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) {
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
Error_Set_File_Info:
|
||||
Error_Get_File_Size:
|
||||
Error_Get_FileName:
|
||||
Error_Resolve_Symlink:
|
||||
if (NewFileEntryData != NULL) {
|
||||
FreePool (NewFileEntryData);
|
||||
}
|
||||
|
||||
Error_Find_Fe:
|
||||
if (NewFileIdentifierDesc != NULL) {
|
||||
FreePool ((VOID *)NewFileIdentifierDesc);
|
||||
}
|
||||
|
||||
Done:
|
||||
Error_File_Beyond_The_Eof:
|
||||
Error_Invalid_Params:
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Close the file handle.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
|
||||
@retval EFI_SUCCESS The file was closed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfClose (
|
||||
IN EFI_FILE_PROTOCOL *This
|
||||
)
|
||||
{
|
||||
EFI_TPL OldTpl;
|
||||
EFI_STATUS Status;
|
||||
PRIVATE_UDF_FILE_DATA *PrivFileData;
|
||||
PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
|
||||
|
||||
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
if (This == NULL) {
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
|
||||
|
||||
PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
|
||||
|
||||
if (!PrivFileData->IsRootDirectory) {
|
||||
CleanupFileInformation (&PrivFileData->File);
|
||||
|
||||
if (PrivFileData->ReadDirInfo.DirectoryData != NULL) {
|
||||
FreePool (PrivFileData->ReadDirInfo.DirectoryData);
|
||||
}
|
||||
}
|
||||
|
||||
if (--PrivFsData->OpenFiles == 0) {
|
||||
CleanupVolumeInformation (&PrivFsData->Volume);
|
||||
}
|
||||
|
||||
FreePool ((VOID *)PrivFileData);
|
||||
|
||||
Exit:
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Close and delete the file handle.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
|
||||
@retval EFI_SUCCESS The file was closed and deleted.
|
||||
@retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not
|
||||
deleted.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfDelete (
|
||||
IN EFI_FILE_PROTOCOL *This
|
||||
)
|
||||
{
|
||||
PRIVATE_UDF_FILE_DATA *PrivFileData;
|
||||
|
||||
if (This == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
|
||||
|
||||
(VOID)PrivFileData->FileIo.Close(This);
|
||||
|
||||
return EFI_WARN_DELETE_FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
Write data to a file.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param BufferSize On input size of buffer, on output amount of data in
|
||||
buffer.
|
||||
@param Buffer The buffer in which data to write.
|
||||
|
||||
@retval EFI_SUCCESS Data was written.
|
||||
@retval EFI_UNSUPPORTED Writes to Open directory are not supported.
|
||||
@retval EFI_NO_MEDIA The device has no media.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error.
|
||||
@retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
|
||||
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
|
||||
@retval EFI_WRITE_PROTECTED The device is write protected.
|
||||
@retval EFI_ACCESS_DENIED The file was open for read only.
|
||||
@retval EFI_VOLUME_FULL The volume is full.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfWrite (
|
||||
IN EFI_FILE_PROTOCOL *This,
|
||||
IN OUT UINTN *BufferSize,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
Get file's current position.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param Position Byte position from the start of the file.
|
||||
|
||||
@retval EFI_SUCCESS Position was updated.
|
||||
@retval EFI_UNSUPPORTED Seek request for directories is not valid.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfGetPosition (
|
||||
IN EFI_FILE_PROTOCOL *This,
|
||||
OUT UINT64 *Position
|
||||
)
|
||||
{
|
||||
PRIVATE_UDF_FILE_DATA *PrivFileData;
|
||||
|
||||
if (This == NULL || Position == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
|
||||
|
||||
//
|
||||
// As per UEFI spec, if the file handle is a directory, then the current file
|
||||
// position has no meaning and the operation is not supported.
|
||||
//
|
||||
if (IS_FID_DIRECTORY_FILE (&PrivFileData->File.FileIdentifierDesc)) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// The file is not a directory. So, return its position.
|
||||
//
|
||||
*Position = PrivFileData->FilePosition;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Set file's current position.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param Position Byte position from the start of the file.
|
||||
|
||||
@retval EFI_SUCCESS Position was updated.
|
||||
@retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfSetPosition (
|
||||
IN EFI_FILE_PROTOCOL *This,
|
||||
IN UINT64 Position
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
PRIVATE_UDF_FILE_DATA *PrivFileData;
|
||||
UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
|
||||
|
||||
if (This == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Status = EFI_UNSUPPORTED;
|
||||
|
||||
PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
|
||||
|
||||
FileIdentifierDesc = PrivFileData->File.FileIdentifierDesc;
|
||||
if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) {
|
||||
//
|
||||
// If the file handle is a directory, the _only_ position that may be set is
|
||||
// zero. This has no effect of starting the read proccess of the directory
|
||||
// entries over.
|
||||
//
|
||||
if (Position == 0) {
|
||||
PrivFileData->FilePosition = Position;
|
||||
PrivFileData->ReadDirInfo.FidOffset = 0;
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
} else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) {
|
||||
//
|
||||
// Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be
|
||||
// set to the EOF.
|
||||
//
|
||||
if (Position == 0xFFFFFFFFFFFFFFFF) {
|
||||
PrivFileData->FilePosition = PrivFileData->FileSize - 1;
|
||||
} else {
|
||||
PrivFileData->FilePosition = Position;
|
||||
}
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Get information about a file.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param InformationType Type of information to return in Buffer.
|
||||
@param BufferSize On input size of buffer, on output amount of data in
|
||||
buffer.
|
||||
@param Buffer The buffer to return data.
|
||||
|
||||
@retval EFI_SUCCESS Data was returned.
|
||||
@retval EFI_UNSUPPORTED InformationType is not supported.
|
||||
@retval EFI_NO_MEDIA The device has no media.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error.
|
||||
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
|
||||
@retval EFI_WRITE_PROTECTED The device is write protected.
|
||||
@retval EFI_ACCESS_DENIED The file was open for read only.
|
||||
@retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
|
||||
BufferSize.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfGetInfo (
|
||||
IN EFI_FILE_PROTOCOL *This,
|
||||
IN EFI_GUID *InformationType,
|
||||
IN OUT UINTN *BufferSize,
|
||||
OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
PRIVATE_UDF_FILE_DATA *PrivFileData;
|
||||
PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
|
||||
EFI_FILE_SYSTEM_INFO *FileSystemInfo;
|
||||
UINTN FileSystemInfoLength;
|
||||
CHAR16 *String;
|
||||
UDF_FILE_SET_DESCRIPTOR *FileSetDesc;
|
||||
UINTN Index;
|
||||
UINT8 *OstaCompressed;
|
||||
UINT8 CompressionId;
|
||||
UINT64 VolumeSize;
|
||||
UINT64 FreeSpaceSize;
|
||||
CHAR16 VolumeLabel[64];
|
||||
|
||||
if (This == NULL || InformationType == NULL || BufferSize == NULL ||
|
||||
(*BufferSize != 0 && Buffer == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
|
||||
|
||||
PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
|
||||
|
||||
Status = EFI_UNSUPPORTED;
|
||||
|
||||
if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
|
||||
Status = SetFileInfo (
|
||||
_FILE (PrivFileData),
|
||||
PrivFileData->FileSize,
|
||||
PrivFileData->FileName,
|
||||
BufferSize,
|
||||
Buffer
|
||||
);
|
||||
} else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
|
||||
String = VolumeLabel;
|
||||
|
||||
FileSetDesc = PrivFsData->Volume.FileSetDescs[0];
|
||||
|
||||
OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];
|
||||
|
||||
CompressionId = OstaCompressed[0];
|
||||
if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
for (Index = 1; Index < 128; Index++) {
|
||||
if (CompressionId == 16) {
|
||||
*String = *(UINT8 *)(OstaCompressed + Index) << 8;
|
||||
Index++;
|
||||
} else {
|
||||
*String = 0;
|
||||
}
|
||||
|
||||
if (Index < 128) {
|
||||
*String |= *(UINT8 *)(OstaCompressed + Index);
|
||||
}
|
||||
|
||||
//
|
||||
// Unlike FID Identifiers, Logical Volume Identifier is stored in a
|
||||
// NULL-terminated OSTA compressed format, so we must check for the NULL
|
||||
// character.
|
||||
//
|
||||
if (*String == L'\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
String++;
|
||||
}
|
||||
|
||||
*String = L'\0';
|
||||
|
||||
FileSystemInfoLength = StrSize (VolumeLabel) +
|
||||
sizeof (EFI_FILE_SYSTEM_INFO);
|
||||
if (*BufferSize < FileSystemInfoLength) {
|
||||
*BufferSize = FileSystemInfoLength;
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
|
||||
StrCpyS (FileSystemInfo->VolumeLabel, ARRAY_SIZE (VolumeLabel),
|
||||
VolumeLabel);
|
||||
Status = GetVolumeSize (
|
||||
PrivFsData->BlockIo,
|
||||
PrivFsData->DiskIo,
|
||||
&PrivFsData->Volume,
|
||||
&VolumeSize,
|
||||
&FreeSpaceSize
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
FileSystemInfo->Size = FileSystemInfoLength;
|
||||
FileSystemInfo->ReadOnly = TRUE;
|
||||
FileSystemInfo->BlockSize =
|
||||
LV_BLOCK_SIZE (&PrivFsData->Volume, UDF_DEFAULT_LV_NUM);
|
||||
FileSystemInfo->VolumeSize = VolumeSize;
|
||||
FileSystemInfo->FreeSpace = FreeSpaceSize;
|
||||
|
||||
*BufferSize = FileSystemInfoLength;
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Set information about a file.
|
||||
|
||||
@param File Protocol instance pointer.
|
||||
@param InformationType Type of information in Buffer.
|
||||
@param BufferSize Size of buffer.
|
||||
@param Buffer The data to write.
|
||||
|
||||
@retval EFI_SUCCESS Data was set.
|
||||
@retval EFI_UNSUPPORTED InformationType is not supported.
|
||||
@retval EFI_NO_MEDIA The device has no media.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error.
|
||||
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
|
||||
@retval EFI_WRITE_PROTECTED The device is write protected.
|
||||
@retval EFI_ACCESS_DENIED The file was open for read only.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfSetInfo (
|
||||
IN EFI_FILE_PROTOCOL *This,
|
||||
IN EFI_GUID *InformationType,
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
return EFI_WRITE_PROTECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
Flush data back for the file handle.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
|
||||
@retval EFI_SUCCESS Data was flushed.
|
||||
@retval EFI_UNSUPPORTED Writes to Open directory are not supported.
|
||||
@retval EFI_NO_MEDIA The device has no media.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error.
|
||||
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
|
||||
@retval EFI_WRITE_PROTECTED The device is write protected.
|
||||
@retval EFI_ACCESS_DENIED The file was open for read only.
|
||||
@retval EFI_VOLUME_FULL The volume is full.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfFlush (
|
||||
IN EFI_FILE_PROTOCOL *This
|
||||
)
|
||||
{
|
||||
return EFI_WRITE_PROTECTED;
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
/** @file
|
||||
Helper functions for mangling file names in UDF/ECMA-167 file systems.
|
||||
|
||||
Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
|
||||
|
||||
This program and the accompanying materials are licensed and made available
|
||||
under the terms and conditions of the BSD License which accompanies this
|
||||
distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include "Udf.h"
|
||||
|
||||
CHAR16 *
|
||||
TrimString (
|
||||
IN CHAR16 *String
|
||||
)
|
||||
{
|
||||
CHAR16 *TempString;
|
||||
|
||||
for ( ; *String != L'\0' && *String == L' '; String++) {
|
||||
;
|
||||
}
|
||||
|
||||
TempString = String + StrLen (String) - 1;
|
||||
while ((TempString >= String) && (*TempString == L' ')) {
|
||||
TempString--;
|
||||
}
|
||||
|
||||
*(TempString + 1) = L'\0';
|
||||
|
||||
return String;
|
||||
}
|
||||
|
||||
VOID
|
||||
ReplaceLeft (
|
||||
IN CHAR16 *Destination,
|
||||
IN CONST CHAR16 *Source
|
||||
)
|
||||
{
|
||||
CONST CHAR16 *EndString;
|
||||
|
||||
EndString = Source + StrLen (Source);
|
||||
while (Source <= EndString) {
|
||||
*Destination++ = *Source++;
|
||||
}
|
||||
}
|
||||
|
||||
CHAR16 *
|
||||
ExcludeTrailingBackslashes (
|
||||
IN CHAR16 *String
|
||||
)
|
||||
{
|
||||
CHAR16 *TempString;
|
||||
|
||||
switch (*(String + 1)) {
|
||||
case L'\\':
|
||||
break;
|
||||
case L'\0':
|
||||
default:
|
||||
String++;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
TempString = String;
|
||||
while (*TempString != L'\0' && *TempString == L'\\') {
|
||||
TempString++;
|
||||
}
|
||||
|
||||
if (TempString - 1 > String) {
|
||||
ReplaceLeft (String + 1, TempString);
|
||||
}
|
||||
|
||||
String++;
|
||||
|
||||
Exit:
|
||||
return String;
|
||||
}
|
||||
|
||||
/**
|
||||
Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..".
|
||||
|
||||
@param[in] FileName Filename.
|
||||
|
||||
@retval @p FileName Filename mangled.
|
||||
|
||||
**/
|
||||
CHAR16 *
|
||||
MangleFileName (
|
||||
IN CHAR16 *FileName
|
||||
)
|
||||
{
|
||||
CHAR16 *FileNameSavedPointer;
|
||||
CHAR16 *TempFileName;
|
||||
UINTN BackslashesNo;
|
||||
|
||||
if (FileName == NULL || *FileName == L'\0') {
|
||||
FileName = NULL;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
FileName = TrimString (FileName);
|
||||
if (*FileName == L'\0') {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ((StrLen (FileName) > 1) && (FileName[StrLen (FileName) - 1] == L'\\')) {
|
||||
FileName[StrLen (FileName) - 1] = L'\0';
|
||||
}
|
||||
|
||||
FileNameSavedPointer = FileName;
|
||||
|
||||
if (FileName[0] == L'.') {
|
||||
if (FileName[1] == L'.') {
|
||||
if (FileName[2] == L'\0') {
|
||||
goto Exit;
|
||||
} else {
|
||||
FileName += 2;
|
||||
}
|
||||
} else if (FileName[1] == L'\0') {
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
while (*FileName != L'\0') {
|
||||
if (*FileName == L'\\') {
|
||||
FileName = ExcludeTrailingBackslashes (FileName);
|
||||
} else if (*FileName == L'.') {
|
||||
switch (*(FileName + 1)) {
|
||||
case L'\0':
|
||||
*FileName = L'\0';
|
||||
break;
|
||||
case L'\\':
|
||||
TempFileName = FileName + 1;
|
||||
TempFileName = ExcludeTrailingBackslashes (TempFileName);
|
||||
ReplaceLeft (FileName, TempFileName);
|
||||
break;
|
||||
case '.':
|
||||
if ((*(FileName - 1) != L'\\') && ((*(FileName + 2) != L'\\') ||
|
||||
(*(FileName + 2) != L'\0'))) {
|
||||
FileName++;
|
||||
continue;
|
||||
}
|
||||
|
||||
BackslashesNo = 0;
|
||||
TempFileName = FileName - 1;
|
||||
while (TempFileName >= FileNameSavedPointer) {
|
||||
if (*TempFileName == L'\\') {
|
||||
if (++BackslashesNo == 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TempFileName--;
|
||||
}
|
||||
|
||||
TempFileName++;
|
||||
|
||||
if ((*TempFileName == L'.') && (*(TempFileName + 1) == L'.')) {
|
||||
FileName += 2;
|
||||
} else {
|
||||
if (*(FileName + 2) != L'\0') {
|
||||
ReplaceLeft (TempFileName, FileName + 3);
|
||||
if (*(TempFileName - 1) == L'\\') {
|
||||
FileName = TempFileName;
|
||||
ExcludeTrailingBackslashes (TempFileName - 1);
|
||||
TempFileName = FileName;
|
||||
}
|
||||
} else {
|
||||
*TempFileName = L'\0';
|
||||
}
|
||||
|
||||
FileName = TempFileName;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
FileName++;
|
||||
}
|
||||
} else {
|
||||
FileName++;
|
||||
}
|
||||
}
|
||||
|
||||
FileName = FileNameSavedPointer;
|
||||
if ((StrLen (FileName) > 1) && (FileName [StrLen (FileName) - 1] == L'\\')) {
|
||||
FileName [StrLen (FileName) - 1] = L'\0';
|
||||
}
|
||||
|
||||
Exit:
|
||||
return FileName;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,344 @@
|
|||
/** @file
|
||||
UDF/ECMA-167 file system driver.
|
||||
|
||||
Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
|
||||
|
||||
This program and the accompanying materials are licensed and made available
|
||||
under the terms and conditions of the BSD License which accompanies this
|
||||
distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include "Udf.h"
|
||||
|
||||
//
|
||||
// UDF filesystem driver's Global Variables.
|
||||
//
|
||||
EFI_DRIVER_BINDING_PROTOCOL gUdfDriverBinding = {
|
||||
UdfDriverBindingSupported,
|
||||
UdfDriverBindingStart,
|
||||
UdfDriverBindingStop,
|
||||
0x10,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gUdfSimpleFsTemplate = {
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
|
||||
UdfOpenVolume
|
||||
};
|
||||
|
||||
/**
|
||||
Test to see if this driver supports ControllerHandle. Any ControllerHandle
|
||||
than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
|
||||
supported.
|
||||
|
||||
@param[in] This Protocol instance pointer.
|
||||
@param[in] ControllerHandle Handle of device to test.
|
||||
@param[in] RemainingDevicePath Optional parameter use to pick a specific
|
||||
child device to start.
|
||||
|
||||
@retval EFI_SUCCESS This driver supports this device.
|
||||
@retval EFI_ALREADY_STARTED This driver is already running on this device.
|
||||
@retval other This driver does not support this device.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfDriverBindingSupported (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||||
|
||||
//
|
||||
// Open DiskIo protocol on ControllerHandle
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
(VOID **)&DiskIo,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Close DiskIo protocol on ControllerHandle
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
|
||||
//
|
||||
// Test whether ControllerHandle supports BlockIo protocol
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
NULL,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Start this driver on ControllerHandle by opening a Block IO or a Block IO2
|
||||
or both, and Disk IO protocol, reading Device Path, and creating a child
|
||||
handle with a Disk IO and device path protocol.
|
||||
|
||||
@param[in] This Protocol instance pointer.
|
||||
@param[in] ControllerHandle Handle of device to bind driver to
|
||||
@param[in] RemainingDevicePath Optional parameter use to pick a specific
|
||||
child device to start.
|
||||
|
||||
@retval EFI_SUCCESS This driver is added to ControllerHandle.
|
||||
@retval EFI_ALREADY_STARTED This driver is already running on
|
||||
ControllerHandle.
|
||||
@retval other This driver does not support this device.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfDriverBindingStart (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
)
|
||||
{
|
||||
EFI_TPL OldTpl;
|
||||
EFI_STATUS Status;
|
||||
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
||||
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||||
PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
|
||||
|
||||
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
||||
|
||||
//
|
||||
// Open BlockIo protocol on ControllerHandle
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
(VOID **)&BlockIo,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
//
|
||||
// Open DiskIo protocol on ControllerHandle
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
(VOID **)&DiskIo,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
//
|
||||
// Check if ControllerHandle supports an UDF file system
|
||||
//
|
||||
Status = SupportUdfFileSystem (This, ControllerHandle);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize private file system structure
|
||||
//
|
||||
PrivFsData =
|
||||
(PRIVATE_UDF_SIMPLE_FS_DATA *)
|
||||
AllocateZeroPool (sizeof (PRIVATE_UDF_SIMPLE_FS_DATA));
|
||||
if (PrivFsData == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Create new child handle
|
||||
//
|
||||
PrivFsData->Signature = PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE;
|
||||
PrivFsData->BlockIo = BlockIo;
|
||||
PrivFsData->DiskIo = DiskIo;
|
||||
PrivFsData->Handle = ControllerHandle;
|
||||
|
||||
//
|
||||
// Set up SimpleFs protocol
|
||||
//
|
||||
CopyMem ((VOID *)&PrivFsData->SimpleFs, (VOID *)&gUdfSimpleFsTemplate,
|
||||
sizeof (EFI_SIMPLE_FILE_SYSTEM_PROTOCOL));
|
||||
|
||||
//
|
||||
// Install child handle
|
||||
//
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&PrivFsData->Handle,
|
||||
&gEfiSimpleFileSystemProtocolGuid,
|
||||
&PrivFsData->SimpleFs,
|
||||
NULL
|
||||
);
|
||||
|
||||
Exit:
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// Close DiskIo protocol on ControllerHandle
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
//
|
||||
// Close BlockIo protocol on ControllerHandle
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
}
|
||||
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Stop this driver on ControllerHandle. Support stopping any child handles
|
||||
created by this driver.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param ControllerHandle Handle of device to stop driver on
|
||||
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
|
||||
children is zero stop the entire bus driver.
|
||||
@param ChildHandleBuffer List of Child Handles to Stop.
|
||||
|
||||
@retval EFI_SUCCESS This driver is removed ControllerHandle
|
||||
@retval other This driver was not removed from this device
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UdfDriverBindingStop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer
|
||||
)
|
||||
{
|
||||
PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
|
||||
EFI_STATUS Status;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
|
||||
|
||||
//
|
||||
// Open SimpleFs protocol on ControllerHandle
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiSimpleFileSystemProtocolGuid,
|
||||
(VOID **)&SimpleFs,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (SimpleFs);
|
||||
|
||||
//
|
||||
// Uninstall child handle
|
||||
//
|
||||
Status = gBS->UninstallMultipleProtocolInterfaces (
|
||||
PrivFsData->Handle,
|
||||
&gEfiSimpleFileSystemProtocolGuid,
|
||||
&PrivFsData->SimpleFs,
|
||||
NULL
|
||||
);
|
||||
|
||||
//
|
||||
// Check if there's any open file. If so, clean them up.
|
||||
//
|
||||
if (PrivFsData->OpenFiles > 0) {
|
||||
CleanupVolumeInformation (&PrivFsData->Volume);
|
||||
}
|
||||
|
||||
FreePool ((VOID *)PrivFsData);
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
//
|
||||
// Close DiskIo protocol on ControllerHandle
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
//
|
||||
// Close BlockIo protocol on ControllerHandle
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
The user Entry Point for UDF file system driver. The user code starts with
|
||||
this function.
|
||||
|
||||
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
||||
@param[in] SystemTable A pointer to the EFI System Table.
|
||||
|
||||
@retval EFI_SUCCESS The entry point is executed successfully.
|
||||
@retval other Some error occurs when executing this entry point.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InitializeUdf (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = EfiLibInstallDriverBindingComponentName2 (
|
||||
ImageHandle,
|
||||
SystemTable,
|
||||
&gUdfDriverBinding,
|
||||
ImageHandle,
|
||||
&gUdfComponentName,
|
||||
&gUdfComponentName2
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
return Status;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,66 @@
|
|||
## @file
|
||||
# UDF/ECMA-167 file system driver.
|
||||
#
|
||||
# Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
|
||||
#
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = UdfDxe
|
||||
FILE_GUID = 905f13b0-8f91-4b0a-bd76-e1e78f9422e4
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = InitializeUdf
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
|
||||
#
|
||||
# DRIVER_BINDING = gUdfDriverBinding
|
||||
# COMPONENT_NAME = gUdfComponentName
|
||||
# COMPONENT_NAME2 = gUdfComponentName2
|
||||
#
|
||||
|
||||
[Sources]
|
||||
ComponentName.c
|
||||
FileSystemOperations.c
|
||||
FileName.c
|
||||
File.c
|
||||
Udf.c
|
||||
Udf.h
|
||||
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
|
||||
|
||||
[LibraryClasses]
|
||||
DevicePathLib
|
||||
UefiBootServicesTableLib
|
||||
MemoryAllocationLib
|
||||
BaseMemoryLib
|
||||
UefiLib
|
||||
BaseLib
|
||||
UefiDriverEntryPoint
|
||||
DebugLib
|
||||
|
||||
|
||||
[Guids]
|
||||
gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## Protocol
|
||||
gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## Protocol
|
||||
|
||||
|
||||
[Protocols]
|
||||
gEfiSimpleFileSystemProtocolGuid ## BY_START
|
||||
gEfiDevicePathProtocolGuid ## BY_START
|
||||
gEfiBlockIoProtocolGuid ## TO_START
|
||||
gEfiDiskIoProtocolGuid ## TO_START
|
Loading…
Reference in New Issue