123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 |
- /** @file
- Functions that perform file read/write.
- Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Fat.h"
- /**
- Get the file's position of the file.
- @param FHand - The handle of file.
- @param Position - The file's position of the file.
- @retval EFI_SUCCESS - Get the info successfully.
- @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
- @retval EFI_UNSUPPORTED - The open file is not a file.
- **/
- EFI_STATUS
- EFIAPI
- FatGetPosition (
- IN EFI_FILE_PROTOCOL *FHand,
- OUT UINT64 *Position
- )
- {
- FAT_IFILE *IFile;
- FAT_OFILE *OFile;
- IFile = IFILE_FROM_FHAND (FHand);
- OFile = IFile->OFile;
- if (OFile->Error == EFI_NOT_FOUND) {
- return EFI_DEVICE_ERROR;
- }
- if (OFile->ODir != NULL) {
- return EFI_UNSUPPORTED;
- }
- *Position = IFile->Position;
- return EFI_SUCCESS;
- }
- /**
- Set the file's position of the file.
- @param FHand - The handle of file.
- @param Position - The file's position of the file.
- @retval EFI_SUCCESS - Set the info successfully.
- @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
- @retval EFI_UNSUPPORTED - Set a directory with a not-zero position.
- **/
- EFI_STATUS
- EFIAPI
- FatSetPosition (
- IN EFI_FILE_PROTOCOL *FHand,
- IN UINT64 Position
- )
- {
- FAT_IFILE *IFile;
- FAT_OFILE *OFile;
- IFile = IFILE_FROM_FHAND (FHand);
- OFile = IFile->OFile;
- if (OFile->Error == EFI_NOT_FOUND) {
- return EFI_DEVICE_ERROR;
- }
- FatWaitNonblockingTask (IFile);
- //
- // If this is a directory, we can only set back to position 0
- //
- if (OFile->ODir != NULL) {
- if (Position != 0) {
- //
- // Reset current directory cursor;
- //
- return EFI_UNSUPPORTED;
- }
- FatResetODirCursor (OFile);
- }
- //
- // Set the position
- //
- if (Position == (UINT64)-1) {
- Position = OFile->FileSize;
- }
- //
- // Set the position
- //
- IFile->Position = Position;
- return EFI_SUCCESS;
- }
- /**
- Get the file info from the open file of the IFile into Buffer.
- @param IFile - The instance of the open file.
- @param BufferSize - Size of Buffer.
- @param Buffer - Buffer containing read data.
- @retval EFI_SUCCESS - Get the file info successfully.
- @retval other - An error occurred when operation the disk.
- **/
- EFI_STATUS
- FatIFileReadDir (
- IN FAT_IFILE *IFile,
- IN OUT UINTN *BufferSize,
- OUT VOID *Buffer
- )
- {
- EFI_STATUS Status;
- FAT_OFILE *OFile;
- FAT_ODIR *ODir;
- FAT_DIRENT *DirEnt;
- UINT32 CurrentPos;
- OFile = IFile->OFile;
- ODir = OFile->ODir;
- CurrentPos = ((UINT32) IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY);
- //
- // We need to relocate the directory
- //
- if (CurrentPos < ODir->CurrentPos) {
- //
- // The directory cursor has been modified by another IFile, we reset the cursor
- //
- FatResetODirCursor (OFile);
- }
- //
- // We seek the next directory entry's position
- //
- do {
- Status = FatGetNextDirEnt (OFile, &DirEnt);
- if (EFI_ERROR (Status) || DirEnt == NULL) {
- //
- // Something error occurred or reach the end of directory,
- // return 0 buffersize
- //
- *BufferSize = 0;
- goto Done;
- }
- } while (ODir->CurrentPos <= CurrentPos);
- Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer);
- Done:
- //
- // Update IFile's Position
- //
- if (!EFI_ERROR (Status)) {
- //
- // Update IFile->Position, if everything is all right
- //
- CurrentPos = ODir->CurrentPos;
- IFile->Position = CurrentPos * sizeof (FAT_DIRECTORY_ENTRY);
- }
- return Status;
- }
- /**
- Get the file info from the open file of the IFile into Buffer.
- @param FHand - The file handle to access.
- @param IoMode - Indicate whether the access mode is reading or writing.
- @param BufferSize - Size of Buffer.
- @param Buffer - Buffer containing read data.
- @param Token - A pointer to the token associated with the transaction.
- @retval EFI_SUCCESS - Get the file info successfully.
- @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
- @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
- @retval EFI_WRITE_PROTECTED - The disk is write protect.
- @retval EFI_ACCESS_DENIED - The file is read-only.
- @return other - An error occurred when operating on the disk.
- **/
- EFI_STATUS
- FatIFileAccess (
- IN EFI_FILE_PROTOCOL *FHand,
- IN IO_MODE IoMode,
- IN OUT UINTN *BufferSize,
- IN OUT VOID *Buffer,
- IN EFI_FILE_IO_TOKEN *Token
- )
- {
- EFI_STATUS Status;
- FAT_IFILE *IFile;
- FAT_OFILE *OFile;
- FAT_VOLUME *Volume;
- UINT64 EndPosition;
- FAT_TASK *Task;
- IFile = IFILE_FROM_FHAND (FHand);
- OFile = IFile->OFile;
- Volume = OFile->Volume;
- Task = NULL;
- //
- // Write to a directory is unsupported
- //
- if ((OFile->ODir != NULL) && (IoMode == WriteData)) {
- return EFI_UNSUPPORTED;
- }
- if (OFile->Error == EFI_NOT_FOUND) {
- return EFI_DEVICE_ERROR;
- }
- if (IoMode == ReadData) {
- //
- // If position is at EOF, then return device error
- //
- if (IFile->Position > OFile->FileSize) {
- return EFI_DEVICE_ERROR;
- }
- } else {
- //
- // Check if the we can write data
- //
- if (Volume->ReadOnly) {
- return EFI_WRITE_PROTECTED;
- }
- if (IFile->ReadOnly) {
- return EFI_ACCESS_DENIED;
- }
- }
- if (Token == NULL) {
- FatWaitNonblockingTask (IFile);
- } else {
- //
- // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.
- // But if it calls, the below check can avoid crash.
- //
- if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {
- return EFI_UNSUPPORTED;
- }
- Task = FatCreateTask (IFile, Token);
- if (Task == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
- FatAcquireLock ();
- Status = OFile->Error;
- if (!EFI_ERROR (Status)) {
- if (OFile->ODir != NULL) {
- //
- // Read a directory is supported
- //
- ASSERT (IoMode == ReadData);
- Status = FatIFileReadDir (IFile, BufferSize, Buffer);
- OFile = NULL;
- } else {
- //
- // Access a file
- //
- EndPosition = IFile->Position + *BufferSize;
- if (EndPosition > OFile->FileSize) {
- //
- // The position goes beyond the end of file
- //
- if (IoMode == ReadData) {
- //
- // Adjust the actual size read
- //
- *BufferSize -= (UINTN) EndPosition - OFile->FileSize;
- } else {
- //
- // We expand the file size of OFile
- //
- Status = FatGrowEof (OFile, EndPosition);
- if (EFI_ERROR (Status)) {
- //
- // Must update the file's info into the file's Directory Entry
- // and then flush the dirty cache info into disk.
- //
- *BufferSize = 0;
- FatOFileFlush (OFile);
- OFile = NULL;
- goto Done;
- }
- FatUpdateDirEntClusterSizeInfo (OFile);
- }
- }
- Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer, Task);
- IFile->Position += *BufferSize;
- }
- }
- if (Token != NULL) {
- if (!EFI_ERROR (Status)) {
- Status = FatQueueTask (IFile, Task);
- } else {
- FatDestroyTask (Task);
- }
- }
- Done:
- //
- // On EFI_SUCCESS case, not calling FatCleanupVolume():
- // 1) The Cache flush operation is avoided to enhance
- // performance. Caller is responsible to call Flush() when necessary.
- // 2) The volume dirty bit is probably set already, and is expected to be
- // cleaned in subsequent Flush() or other operations.
- // 3) Write operation doesn't affect OFile/IFile structure, so
- // Reference checking is not necessary.
- //
- if (EFI_ERROR (Status)) {
- Status = FatCleanupVolume (Volume, OFile, Status, NULL);
- }
- FatReleaseLock ();
- return Status;
- }
- /**
- Get the file info.
- @param FHand - The handle of the file.
- @param BufferSize - Size of Buffer.
- @param Buffer - Buffer containing read data.
- @retval EFI_SUCCESS - Get the file info successfully.
- @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
- @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
- @return other - An error occurred when operation the disk.
- **/
- EFI_STATUS
- EFIAPI
- FatRead (
- IN EFI_FILE_PROTOCOL *FHand,
- IN OUT UINTN *BufferSize,
- OUT VOID *Buffer
- )
- {
- return FatIFileAccess (FHand, ReadData, BufferSize, Buffer, NULL);
- }
- /**
- Get the file info.
- @param FHand - The handle of the file.
- @param Token - A pointer to the token associated with the transaction.
- @retval EFI_SUCCESS - Get the file info successfully.
- @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
- @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
- @return other - An error occurred when operation the disk.
- **/
- EFI_STATUS
- EFIAPI
- FatReadEx (
- IN EFI_FILE_PROTOCOL *FHand,
- IN OUT EFI_FILE_IO_TOKEN *Token
- )
- {
- return FatIFileAccess (FHand, ReadData, &Token->BufferSize, Token->Buffer, Token);
- }
- /**
- Write the content of buffer into files.
- @param FHand - The handle of the file.
- @param BufferSize - Size of Buffer.
- @param Buffer - Buffer containing write data.
- @retval EFI_SUCCESS - Set the file info successfully.
- @retval EFI_WRITE_PROTECTED - The disk is write protect.
- @retval EFI_ACCESS_DENIED - The file is read-only.
- @retval EFI_DEVICE_ERROR - The OFile is not valid.
- @retval EFI_UNSUPPORTED - The open file is not a file.
- - The writing file size is larger than 4GB.
- @return other - An error occurred when operation the disk.
- **/
- EFI_STATUS
- EFIAPI
- FatWrite (
- IN EFI_FILE_PROTOCOL *FHand,
- IN OUT UINTN *BufferSize,
- IN VOID *Buffer
- )
- {
- return FatIFileAccess (FHand, WriteData, BufferSize, Buffer, NULL);
- }
- /**
- Get the file info.
- @param FHand - The handle of the file.
- @param Token - A pointer to the token associated with the transaction.
- @retval EFI_SUCCESS - Get the file info successfully.
- @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
- @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
- @return other - An error occurred when operation the disk.
- **/
- EFI_STATUS
- EFIAPI
- FatWriteEx (
- IN EFI_FILE_PROTOCOL *FHand,
- IN OUT EFI_FILE_IO_TOKEN *Token
- )
- {
- return FatIFileAccess (FHand, WriteData, &Token->BufferSize, Token->Buffer, Token);
- }
- /**
- This function reads data from a file or writes data to a file.
- It uses OFile->PosRem to determine how much data can be accessed in one time.
- @param OFile - The open file.
- @param IoMode - Indicate whether the access mode is reading or writing.
- @param Position - The position where data will be accessed.
- @param DataBufferSize - Size of Buffer.
- @param UserBuffer - Buffer containing data.
- @param Task point to task instance.
- @retval EFI_SUCCESS - Access the data successfully.
- @return other - An error occurred when operating on the disk.
- **/
- EFI_STATUS
- FatAccessOFile (
- IN FAT_OFILE *OFile,
- IN IO_MODE IoMode,
- IN UINTN Position,
- IN OUT UINTN *DataBufferSize,
- IN OUT UINT8 *UserBuffer,
- IN FAT_TASK *Task
- )
- {
- FAT_VOLUME *Volume;
- UINTN Len;
- EFI_STATUS Status;
- UINTN BufferSize;
- BufferSize = *DataBufferSize;
- Volume = OFile->Volume;
- ASSERT_VOLUME_LOCKED (Volume);
- Status = EFI_SUCCESS;
- while (BufferSize > 0) {
- //
- // Seek the OFile to the file position
- //
- Status = FatOFilePosition (OFile, Position, BufferSize);
- if (EFI_ERROR (Status)) {
- break;
- }
- //
- // Clip length to block run
- //
- Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize;
- //
- // Write the data
- //
- Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer, Task);
- if (EFI_ERROR (Status)) {
- break;
- }
- //
- // Data was successfully accessed
- //
- Position += Len;
- UserBuffer += Len;
- BufferSize -= Len;
- if (IoMode == WriteData) {
- OFile->Dirty = TRUE;
- OFile->Archive = TRUE;
- }
- //
- // Make sure no outbound occurred
- //
- ASSERT (Position <= OFile->FileSize);
- }
- //
- // Update the number of bytes accessed
- //
- *DataBufferSize -= BufferSize;
- return Status;
- }
- /**
- Expand OFile by appending zero bytes at the end of OFile.
- @param OFile - The open file.
- @param ExpandedSize - The number of zero bytes appended at the end of the file.
- @retval EFI_SUCCESS - The file is expanded successfully.
- @return other - An error occurred when expanding file.
- **/
- EFI_STATUS
- FatExpandOFile (
- IN FAT_OFILE *OFile,
- IN UINT64 ExpandedSize
- )
- {
- EFI_STATUS Status;
- UINTN WritePos;
- WritePos = OFile->FileSize;
- Status = FatGrowEof (OFile, ExpandedSize);
- if (!EFI_ERROR (Status)) {
- Status = FatWriteZeroPool (OFile, WritePos);
- }
- return Status;
- }
- /**
- Write zero pool from the WritePos to the end of OFile.
- @param OFile - The open file to write zero pool.
- @param WritePos - The number of zero bytes written.
- @retval EFI_SUCCESS - Write the zero pool successfully.
- @retval EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation.
- @return other - An error occurred when writing disk.
- **/
- EFI_STATUS
- FatWriteZeroPool (
- IN FAT_OFILE *OFile,
- IN UINTN WritePos
- )
- {
- EFI_STATUS Status;
- VOID *ZeroBuffer;
- UINTN AppendedSize;
- UINTN BufferSize;
- UINTN WriteSize;
- AppendedSize = OFile->FileSize - WritePos;
- BufferSize = AppendedSize;
- if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) {
- //
- // If the appended size is larger, maybe we can not allocate the whole
- // memory once. So if the growed size is larger than 10M, we just
- // allocate 10M memory (one healthy system should have 10M available
- // memory), and then write the zerobuffer to the file several times.
- //
- BufferSize = FAT_MAX_ALLOCATE_SIZE;
- }
- ZeroBuffer = AllocateZeroPool (BufferSize);
- if (ZeroBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- do {
- WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize;
- AppendedSize -= WriteSize;
- Status = FatAccessOFile (OFile, WriteData, WritePos, &WriteSize, ZeroBuffer, NULL);
- if (EFI_ERROR (Status)) {
- break;
- }
- WritePos += WriteSize;
- } while (AppendedSize > 0);
- FreePool (ZeroBuffer);
- return Status;
- }
- /**
- Truncate the OFile to smaller file size.
- @param OFile - The open file.
- @param TruncatedSize - The new file size.
- @retval EFI_SUCCESS - The file is truncated successfully.
- @return other - An error occurred when truncating file.
- **/
- EFI_STATUS
- FatTruncateOFile (
- IN FAT_OFILE *OFile,
- IN UINTN TruncatedSize
- )
- {
- OFile->FileSize = TruncatedSize;
- return FatShrinkEof (OFile);
- }
|