| /** @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; | |
| } |