2 Functions that perform file read/write.
4 Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
14 Get the file's position of the file.
17 @param FHand - The handle of file.
18 @param Position - The file's position of the file.
20 @retval EFI_SUCCESS - Get the info successfully.
21 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
22 @retval EFI_UNSUPPORTED - The open file is not a file.
28 IN EFI_FILE_PROTOCOL
*FHand
,
35 IFile
= IFILE_FROM_FHAND (FHand
);
38 if (OFile
->Error
== EFI_NOT_FOUND
) {
39 return EFI_DEVICE_ERROR
;
42 if (OFile
->ODir
!= NULL
) {
43 return EFI_UNSUPPORTED
;
46 *Position
= IFile
->Position
;
52 Set the file's position of the file.
54 @param FHand - The handle of file.
55 @param Position - The file's position of the file.
57 @retval EFI_SUCCESS - Set the info successfully.
58 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
59 @retval EFI_UNSUPPORTED - Set a directory with a not-zero position.
65 IN EFI_FILE_PROTOCOL
*FHand
,
72 IFile
= IFILE_FROM_FHAND (FHand
);
75 if (OFile
->Error
== EFI_NOT_FOUND
) {
76 return EFI_DEVICE_ERROR
;
79 FatWaitNonblockingTask (IFile
);
82 // If this is a directory, we can only set back to position 0
84 if (OFile
->ODir
!= NULL
) {
87 // Reset current directory cursor;
89 return EFI_UNSUPPORTED
;
92 FatResetODirCursor (OFile
);
97 if (Position
== (UINT64
)-1) {
98 Position
= OFile
->FileSize
;
103 IFile
->Position
= Position
;
109 Get the file info from the open file of the IFile into Buffer.
111 @param IFile - The instance of the open file.
112 @param BufferSize - Size of Buffer.
113 @param Buffer - Buffer containing read data.
115 @retval EFI_SUCCESS - Get the file info successfully.
116 @retval other - An error occurred when operation the disk.
122 IN OUT UINTN
*BufferSize
,
132 OFile
= IFile
->OFile
;
134 CurrentPos
= ((UINT32
) IFile
->Position
) / sizeof (FAT_DIRECTORY_ENTRY
);
137 // We need to relocate the directory
139 if (CurrentPos
< ODir
->CurrentPos
) {
141 // The directory cursor has been modified by another IFile, we reset the cursor
143 FatResetODirCursor (OFile
);
146 // We seek the next directory entry's position
149 Status
= FatGetNextDirEnt (OFile
, &DirEnt
);
150 if (EFI_ERROR (Status
) || DirEnt
== NULL
) {
152 // Something error occurred or reach the end of directory,
153 // return 0 buffersize
158 } while (ODir
->CurrentPos
<= CurrentPos
);
159 Status
= FatGetDirEntInfo (OFile
->Volume
, DirEnt
, BufferSize
, Buffer
);
163 // Update IFile's Position
165 if (!EFI_ERROR (Status
)) {
167 // Update IFile->Position, if everything is all right
169 CurrentPos
= ODir
->CurrentPos
;
170 IFile
->Position
= CurrentPos
* sizeof (FAT_DIRECTORY_ENTRY
);
178 Get the file info from the open file of the IFile into Buffer.
180 @param FHand - The file handle to access.
181 @param IoMode - Indicate whether the access mode is reading or writing.
182 @param BufferSize - Size of Buffer.
183 @param Buffer - Buffer containing read data.
184 @param Token - A pointer to the token associated with the transaction.
186 @retval EFI_SUCCESS - Get the file info successfully.
187 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
188 @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
189 @retval EFI_WRITE_PROTECTED - The disk is write protect.
190 @retval EFI_ACCESS_DENIED - The file is read-only.
191 @return other - An error occurred when operating on the disk.
196 IN EFI_FILE_PROTOCOL
*FHand
,
198 IN OUT UINTN
*BufferSize
,
200 IN EFI_FILE_IO_TOKEN
*Token
210 IFile
= IFILE_FROM_FHAND (FHand
);
211 OFile
= IFile
->OFile
;
212 Volume
= OFile
->Volume
;
216 // Write to a directory is unsupported
218 if ((OFile
->ODir
!= NULL
) && (IoMode
== WriteData
)) {
219 return EFI_UNSUPPORTED
;
222 if (OFile
->Error
== EFI_NOT_FOUND
) {
223 return EFI_DEVICE_ERROR
;
226 if (IoMode
== ReadData
) {
228 // If position is at EOF, then return device error
230 if (IFile
->Position
> OFile
->FileSize
) {
231 return EFI_DEVICE_ERROR
;
235 // Check if the we can write data
237 if (Volume
->ReadOnly
) {
238 return EFI_WRITE_PROTECTED
;
241 if (IFile
->ReadOnly
) {
242 return EFI_ACCESS_DENIED
;
247 FatWaitNonblockingTask (IFile
);
250 // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.
251 // But if it calls, the below check can avoid crash.
253 if (FHand
->Revision
< EFI_FILE_PROTOCOL_REVISION2
) {
254 return EFI_UNSUPPORTED
;
256 Task
= FatCreateTask (IFile
, Token
);
258 return EFI_OUT_OF_RESOURCES
;
264 Status
= OFile
->Error
;
265 if (!EFI_ERROR (Status
)) {
266 if (OFile
->ODir
!= NULL
) {
268 // Read a directory is supported
270 ASSERT (IoMode
== ReadData
);
271 Status
= FatIFileReadDir (IFile
, BufferSize
, Buffer
);
277 EndPosition
= IFile
->Position
+ *BufferSize
;
278 if (EndPosition
> OFile
->FileSize
) {
280 // The position goes beyond the end of file
282 if (IoMode
== ReadData
) {
284 // Adjust the actual size read
286 *BufferSize
-= (UINTN
) EndPosition
- OFile
->FileSize
;
289 // We expand the file size of OFile
291 Status
= FatGrowEof (OFile
, EndPosition
);
292 if (EFI_ERROR (Status
)) {
294 // Must update the file's info into the file's Directory Entry
295 // and then flush the dirty cache info into disk.
298 FatOFileFlush (OFile
);
303 FatUpdateDirEntClusterSizeInfo (OFile
);
307 Status
= FatAccessOFile (OFile
, IoMode
, (UINTN
) IFile
->Position
, BufferSize
, Buffer
, Task
);
308 IFile
->Position
+= *BufferSize
;
313 if (!EFI_ERROR (Status
)) {
314 Status
= FatQueueTask (IFile
, Task
);
316 FatDestroyTask (Task
);
322 // On EFI_SUCCESS case, not calling FatCleanupVolume():
323 // 1) The Cache flush operation is avoided to enhance
324 // performance. Caller is responsible to call Flush() when necessary.
325 // 2) The volume dirty bit is probably set already, and is expected to be
326 // cleaned in subsequent Flush() or other operations.
327 // 3) Write operation doesn't affect OFile/IFile structure, so
328 // Reference checking is not necessary.
330 if (EFI_ERROR (Status
)) {
331 Status
= FatCleanupVolume (Volume
, OFile
, Status
, NULL
);
342 @param FHand - The handle of the file.
343 @param BufferSize - Size of Buffer.
344 @param Buffer - Buffer containing read data.
347 @retval EFI_SUCCESS - Get the file info successfully.
348 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
349 @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
350 @return other - An error occurred when operation the disk.
356 IN EFI_FILE_PROTOCOL
*FHand
,
357 IN OUT UINTN
*BufferSize
,
361 return FatIFileAccess (FHand
, ReadData
, BufferSize
, Buffer
, NULL
);
368 @param FHand - The handle of the file.
369 @param Token - A pointer to the token associated with the transaction.
371 @retval EFI_SUCCESS - Get the file info successfully.
372 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
373 @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
374 @return other - An error occurred when operation the disk.
380 IN EFI_FILE_PROTOCOL
*FHand
,
381 IN OUT EFI_FILE_IO_TOKEN
*Token
384 return FatIFileAccess (FHand
, ReadData
, &Token
->BufferSize
, Token
->Buffer
, Token
);
389 Write the content of buffer into files.
391 @param FHand - The handle of the file.
392 @param BufferSize - Size of Buffer.
393 @param Buffer - Buffer containing write data.
395 @retval EFI_SUCCESS - Set the file info successfully.
396 @retval EFI_WRITE_PROTECTED - The disk is write protect.
397 @retval EFI_ACCESS_DENIED - The file is read-only.
398 @retval EFI_DEVICE_ERROR - The OFile is not valid.
399 @retval EFI_UNSUPPORTED - The open file is not a file.
400 - The writing file size is larger than 4GB.
401 @return other - An error occurred when operation the disk.
407 IN EFI_FILE_PROTOCOL
*FHand
,
408 IN OUT UINTN
*BufferSize
,
412 return FatIFileAccess (FHand
, WriteData
, BufferSize
, Buffer
, NULL
);
419 @param FHand - The handle of the file.
420 @param Token - A pointer to the token associated with the transaction.
422 @retval EFI_SUCCESS - Get the file info successfully.
423 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
424 @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
425 @return other - An error occurred when operation the disk.
431 IN EFI_FILE_PROTOCOL
*FHand
,
432 IN OUT EFI_FILE_IO_TOKEN
*Token
435 return FatIFileAccess (FHand
, WriteData
, &Token
->BufferSize
, Token
->Buffer
, Token
);
440 This function reads data from a file or writes data to a file.
441 It uses OFile->PosRem to determine how much data can be accessed in one time.
443 @param OFile - The open file.
444 @param IoMode - Indicate whether the access mode is reading or writing.
445 @param Position - The position where data will be accessed.
446 @param DataBufferSize - Size of Buffer.
447 @param UserBuffer - Buffer containing data.
448 @param Task point to task instance.
450 @retval EFI_SUCCESS - Access the data successfully.
451 @return other - An error occurred when operating on the disk.
459 IN OUT UINTN
*DataBufferSize
,
460 IN OUT UINT8
*UserBuffer
,
469 BufferSize
= *DataBufferSize
;
470 Volume
= OFile
->Volume
;
471 ASSERT_VOLUME_LOCKED (Volume
);
473 Status
= EFI_SUCCESS
;
474 while (BufferSize
> 0) {
476 // Seek the OFile to the file position
478 Status
= FatOFilePosition (OFile
, Position
, BufferSize
);
479 if (EFI_ERROR (Status
)) {
483 // Clip length to block run
485 Len
= BufferSize
> OFile
->PosRem
? OFile
->PosRem
: BufferSize
;
490 Status
= FatDiskIo (Volume
, IoMode
, OFile
->PosDisk
, Len
, UserBuffer
, Task
);
491 if (EFI_ERROR (Status
)) {
495 // Data was successfully accessed
500 if (IoMode
== WriteData
) {
502 OFile
->Archive
= TRUE
;
505 // Make sure no outbound occurred
507 ASSERT (Position
<= OFile
->FileSize
);
510 // Update the number of bytes accessed
512 *DataBufferSize
-= BufferSize
;
518 Expand OFile by appending zero bytes at the end of OFile.
520 @param OFile - The open file.
521 @param ExpandedSize - The number of zero bytes appended at the end of the file.
523 @retval EFI_SUCCESS - The file is expanded successfully.
524 @return other - An error occurred when expanding file.
530 IN UINT64 ExpandedSize
536 WritePos
= OFile
->FileSize
;
537 Status
= FatGrowEof (OFile
, ExpandedSize
);
538 if (!EFI_ERROR (Status
)) {
539 Status
= FatWriteZeroPool (OFile
, WritePos
);
547 Write zero pool from the WritePos to the end of OFile.
549 @param OFile - The open file to write zero pool.
550 @param WritePos - The number of zero bytes written.
552 @retval EFI_SUCCESS - Write the zero pool successfully.
553 @retval EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation.
554 @return other - An error occurred when writing disk.
569 AppendedSize
= OFile
->FileSize
- WritePos
;
570 BufferSize
= AppendedSize
;
571 if (AppendedSize
> FAT_MAX_ALLOCATE_SIZE
) {
573 // If the appended size is larger, maybe we can not allocate the whole
574 // memory once. So if the growed size is larger than 10M, we just
575 // allocate 10M memory (one healthy system should have 10M available
576 // memory), and then write the zerobuffer to the file several times.
578 BufferSize
= FAT_MAX_ALLOCATE_SIZE
;
581 ZeroBuffer
= AllocateZeroPool (BufferSize
);
582 if (ZeroBuffer
== NULL
) {
583 return EFI_OUT_OF_RESOURCES
;
587 WriteSize
= AppendedSize
> BufferSize
? BufferSize
: (UINTN
) AppendedSize
;
588 AppendedSize
-= WriteSize
;
589 Status
= FatAccessOFile (OFile
, WriteData
, WritePos
, &WriteSize
, ZeroBuffer
, NULL
);
590 if (EFI_ERROR (Status
)) {
594 WritePos
+= WriteSize
;
595 } while (AppendedSize
> 0);
597 FreePool (ZeroBuffer
);
603 Truncate the OFile to smaller file size.
605 @param OFile - The open file.
606 @param TruncatedSize - The new file size.
608 @retval EFI_SUCCESS - The file is truncated successfully.
609 @return other - An error occurred when truncating file.
615 IN UINTN TruncatedSize
618 OFile
->FileSize
= TruncatedSize
;
619 return FatShrinkEof (OFile
);