__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout MdeModulePkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
		
			
				
	
	
		
			918 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			918 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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;
 | 
						|
}
 |