/** @file | |
Handle operations in files and directories from UDF/ECMA-167 file systems. | |
Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com> | |
Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#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: | |
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]; | |
UDF_FILE_INFO File; | |
PRIVATE_UDF_FILE_DATA *NewPrivFileData; | |
CHAR16 *TempFileName; | |
ZeroMem (FilePath, sizeof FilePath); | |
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_FILENAME_LENGTH, FileName); | |
Status = GetFileSize ( | |
PrivFsData->BlockIo, | |
PrivFsData->DiskIo, | |
&PrivFsData->Volume, | |
&NewPrivFileData->File, | |
&NewPrivFileData->FileSize | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: GetFileSize() fails with status - %r.\n", | |
__func__, | |
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]; | |
UINT64 FileSize; | |
UINT64 BufferSizeUint64; | |
ZeroMem (FileName, sizeof FileName); | |
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; | |
} | |
// | |
// After calling function ReadDirectoryEntry(), if 'NewFileIdentifierDesc' | |
// is NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the | |
// code reaches here, 'NewFileIdentifierDesc' must be not NULL. | |
// | |
// The ASSERT here is for addressing a false positive NULL pointer | |
// dereference issue raised from static analysis. | |
// | |
ASSERT (NewFileIdentifierDesc != NULL); | |
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; | |
} | |
ASSERT (NewFileEntryData != NULL); | |
if (FE_ICB_FILE_TYPE (NewFileEntryData) == UdfFileEntrySymlink) { | |
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, ARRAY_SIZE (FileName), 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, ARRAY_SIZE (FileName), 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)) { | |
// | |
// Code should never reach here. | |
// | |
ASSERT (FALSE); | |
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; | |
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); | |
if (!PrivFileData->IsRootDirectory) { | |
CleanupFileInformation (&PrivFileData->File); | |
if (PrivFileData->ReadDirInfo.DirectoryData != NULL) { | |
FreePool (PrivFileData->ReadDirInfo.DirectoryData); | |
} | |
} | |
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 = _FILE (PrivFileData)->FileIdentifierDesc; | |
ASSERT (FileIdentifierDesc != NULL); | |
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; | |
} 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; | |
UINT64 VolumeSize; | |
UINT64 FreeSpaceSize; | |
EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel; | |
UINTN FileSystemVolumeLabelLength; | |
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)) { | |
Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
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, | |
(*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_INFO) / sizeof (CHAR16), | |
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 = | |
PrivFsData->Volume.LogicalVolDesc.LogicalBlockSize; | |
FileSystemInfo->VolumeSize = VolumeSize; | |
FileSystemInfo->FreeSpace = FreeSpaceSize; | |
*BufferSize = FileSystemInfoLength; | |
Status = EFI_SUCCESS; | |
} else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { | |
Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
FileSystemVolumeLabelLength = StrSize (VolumeLabel) + | |
sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL); | |
if (*BufferSize < FileSystemVolumeLabelLength) { | |
*BufferSize = FileSystemVolumeLabelLength; | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer; | |
StrCpyS ( | |
FileSystemVolumeLabel->VolumeLabel, | |
(*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL) / sizeof (CHAR16), | |
VolumeLabel | |
); | |
Status = EFI_SUCCESS; | |
} | |
return Status; | |
} | |
/** | |
Set information about a file. | |
@param This 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; | |
} |