diff options
Diffstat (limited to 'MdeModulePkg/Universal/Disk/UdfDxe/File.c')
| -rw-r--r-- | MdeModulePkg/Universal/Disk/UdfDxe/File.c | 1834 |
1 files changed, 917 insertions, 917 deletions
diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/File.c b/MdeModulePkg/Universal/Disk/UdfDxe/File.c index ca2f3e0766..d6c5028a3a 100644 --- a/MdeModulePkg/Universal/Disk/UdfDxe/File.c +++ b/MdeModulePkg/Universal/Disk/UdfDxe/File.c @@ -1,917 +1,917 @@ -/** @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;
-}
+/** @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; +} |
