This patch implements UdfRead(), UdfGetPosition() and UdfSetPosition() functions.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Paulo Alcantara <pca...@zytor.com> --- MdeModulePkg/Universal/Disk/UdfDxe/File.c | 254 ++++++++++++++++++++- .../Universal/Disk/UdfDxe/FileSystemOperations.c | 60 +++++ MdeModulePkg/Universal/Disk/UdfDxe/Udf.h | 33 +++ 3 files changed, 344 insertions(+), 3 deletions(-) diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/File.c b/MdeModulePkg/Universal/Disk/UdfDxe/File.c index f32dcf0..04b6530 100644 --- a/MdeModulePkg/Universal/Disk/UdfDxe/File.c +++ b/MdeModulePkg/Universal/Disk/UdfDxe/File.c @@ -321,7 +321,196 @@ UdfRead ( OUT VOID *Buffer ) { - return EFI_VOLUME_CORRUPTED; + EFI_TPL OldTpl; + EFI_STATUS Status; + PRIVATE_UDF_FILE_DATA *PrivFileData; + PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; + UDF_VOLUME_INFO *Volume; + UDF_FILE_INFO *Parent; + UDF_READ_DIRECTORY_INFO *ReadDirInfo; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + UDF_FILE_INFO FoundFile; + UDF_FILE_IDENTIFIER_DESCRIPTOR *NewFileIdentifierDesc; + VOID *NewFileEntryData; + CHAR16 FileName[UDF_FILENAME_LENGTH] = { 0 }; + UINT64 FileSize; + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (!This || !BufferSize || (*BufferSize && !Buffer)) { + 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; + } + + Status = ReadFileData ( + BlockIo, + DiskIo, + Volume, + Parent, + PrivFileData->FileSize, + &PrivFileData->FilePosition, + Buffer, + BufferSize + ); + } else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) { + if (!ReadDirInfo->FidOffset && PrivFileData->FilePosition) { + Status = EFI_DEVICE_ERROR; + *BufferSize = 0; + goto Done; + } + + for (;;) { + Status = ReadDirectoryEntry ( + BlockIo, + DiskIo, + Volume, + &Parent->FileIdentifierDesc->Icb, + Parent->FileEntry, + ReadDirInfo, + &NewFileIdentifierDesc + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_DEVICE_ERROR) { + FreePool (ReadDirInfo->DirectoryData); + ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO)); + + *BufferSize = 0; + Status = EFI_SUCCESS; + } + + goto Done; + } + + if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) { + break; + } + + FreePool ((VOID *)NewFileIdentifierDesc); + } + + Status = FindFileEntry ( + BlockIo, + DiskIo, + Volume, + &NewFileIdentifierDesc->Icb, + &NewFileEntryData + ); + if (EFI_ERROR (Status)) { + goto Error_Find_Fe; + } + + if (IS_FE_SYMLINK (NewFileEntryData)) { + Status = ResolveSymlink ( + BlockIo, + DiskIo, + Volume, + Parent, + NewFileEntryData, + &FoundFile + ); + if (EFI_ERROR (Status)) { + goto Error_Resolve_Symlink; + } + + FreePool ((VOID *)NewFileEntryData); + NewFileEntryData = FoundFile.FileEntry; + + Status = GetFileNameFromFid (NewFileIdentifierDesc, FileName); + if (EFI_ERROR (Status)) { + FreePool ((VOID *)FoundFile.FileIdentifierDesc); + goto Error_Get_FileName; + } + + FreePool ((VOID *)NewFileIdentifierDesc); + NewFileIdentifierDesc = FoundFile.FileIdentifierDesc; + } else { + FoundFile.FileIdentifierDesc = NewFileIdentifierDesc; + FoundFile.FileEntry = NewFileEntryData; + + Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, FileName); + if (EFI_ERROR (Status)) { + goto Error_Get_FileName; + } + } + + Status = GetFileSize ( + BlockIo, + DiskIo, + Volume, + &FoundFile, + &FileSize + ); + if (EFI_ERROR (Status)) { + goto Error_Get_File_Size; + } + + Status = SetFileInfo ( + &FoundFile, + FileSize, + FileName, + BufferSize, + Buffer + ); + if (EFI_ERROR (Status)) { + goto Error_Set_File_Info; + } + + PrivFileData->FilePosition++; + Status = EFI_SUCCESS; + } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) { + Status = EFI_DEVICE_ERROR; + } + +Error_Set_File_Info: +Error_Get_File_Size: +Error_Get_FileName: +Error_Resolve_Symlink: + if (NewFileEntryData) { + FreePool (NewFileEntryData); + } + +Error_Find_Fe: + if (NewFileIdentifierDesc) { + FreePool ((VOID *)NewFileIdentifierDesc); + } + +Done: +Error_File_Beyond_The_Eof: +Error_Invalid_Params: + gBS->RestoreTPL (OldTpl); + + return Status; } /** @@ -450,7 +639,28 @@ UdfGetPosition ( OUT UINT64 *Position ) { - return EFI_UNSUPPORTED; + PRIVATE_UDF_FILE_DATA *PrivFileData; + + if (!This || !Position) { + 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; } /** @@ -470,7 +680,45 @@ UdfSetPosition ( IN UINT64 Position ) { - return EFI_UNSUPPORTED; + EFI_STATUS Status; + PRIVATE_UDF_FILE_DATA *PrivFileData; + UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc; + + if (!This) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_UNSUPPORTED; + + PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); + + FileIdentifierDesc = PrivFileData->File.FileIdentifierDesc; + if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) { + // + // If the file handle is a directory, the _only_ position that may be set is + // zero. This has no effect of starting the read proccess of the directory + // entries over. + // + if (!Position) { + PrivFileData->FilePosition = Position; + PrivFileData->ReadDirInfo.FidOffset = 0; + Status = EFI_SUCCESS; + } + } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) { + // + // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be + // set to the EOF. + // + if (Position == 0xFFFFFFFFFFFFFFFF) { + PrivFileData->FilePosition = PrivFileData->FileSize - 1; + } else { + PrivFileData->FilePosition = Position; + } + + Status = EFI_SUCCESS; + } + + return Status; } /** diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c b/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c index 65a7af1..829463f 100644 --- a/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c +++ b/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c @@ -2533,3 +2533,63 @@ Read_Next_Sequence: return EFI_SUCCESS; } + +/** + Seek a file and read its data into memory on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] File File information structure. + @param[in] FileSize Size of the file. + @param[in out] FilePosition File position. + @param[in out] Buffer File data. + @param[in out] BufferSize Read size. + + @retval EFI_SUCCESS File seeked and read. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors 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_OUT_OF_RESOURCES The file's recorded data was not read due to lack + of resources. + +**/ +EFI_STATUS +ReadFileData ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_FILE_INFO *File, + IN UINT64 FileSize, + IN OUT UINT64 *FilePosition, + IN OUT VOID *Buffer, + IN OUT UINT64 *BufferSize + ) +{ + EFI_STATUS Status; + UDF_READ_FILE_INFO ReadFileInfo; + + ReadFileInfo.Flags = READ_FILE_SEEK_AND_READ; + ReadFileInfo.FilePosition = *FilePosition; + ReadFileInfo.FileData = Buffer; + ReadFileInfo.FileDataSize = *BufferSize; + ReadFileInfo.FileSize = FileSize; + + Status = ReadFile ( + BlockIo, + DiskIo, + Volume, + &File->FileIdentifierDesc->Icb, + File->FileEntry, + &ReadFileInfo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *BufferSize = ReadFileInfo.FileDataSize; + *FilePosition = ReadFileInfo.FilePosition; + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h b/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h index 14913b7..e3f7c87 100644 --- a/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h +++ b/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h @@ -1032,6 +1032,39 @@ GetVolumeSize ( ); /** + Seek a file and read its data into memory on an UDF volume. + + @param[in] BlockIo BlockIo interface. + @param[in] DiskIo DiskIo interface. + @param[in] Volume UDF volume information structure. + @param[in] File File information structure. + @param[in] FileSize Size of the file. + @param[in out] FilePosition File position. + @param[in out] Buffer File data. + @param[in out] BufferSize Read size. + + @retval EFI_SUCCESS File seeked and read. + @retval EFI_UNSUPPORTED Extended Allocation Descriptors 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_OUT_OF_RESOURCES The file's recorded data was not read due to lack + of resources. + +**/ +EFI_STATUS +ReadFileData ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_DISK_IO_PROTOCOL *DiskIo, + IN UDF_VOLUME_INFO *Volume, + IN UDF_FILE_INFO *File, + IN UINT64 FileSize, + IN OUT UINT64 *FilePosition, + IN OUT VOID *Buffer, + IN OUT UINT64 *BufferSize + ); + +/** Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..". @param[in] FileName Filename. -- 1.9.3 ------------------------------------------------------------------------------ Dive into the World of Parallel Programming! The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel