]> git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/EnhancedFatDxe/ReadWrite.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / ReadWrite.c
1 /** @file
2 Functions that perform file read/write.
3
4 Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7
8 **/
9
10 #include "Fat.h"
11
12 /**
13
14 Get the file's position of the file.
15
16
17 @param FHand - The handle of file.
18 @param Position - The file's position of the file.
19
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.
23
24 **/
25 EFI_STATUS
26 EFIAPI
27 FatGetPosition (
28 IN EFI_FILE_PROTOCOL *FHand,
29 OUT UINT64 *Position
30 )
31 {
32 FAT_IFILE *IFile;
33 FAT_OFILE *OFile;
34
35 IFile = IFILE_FROM_FHAND (FHand);
36 OFile = IFile->OFile;
37
38 if (OFile->Error == EFI_NOT_FOUND) {
39 return EFI_DEVICE_ERROR;
40 }
41
42 if (OFile->ODir != NULL) {
43 return EFI_UNSUPPORTED;
44 }
45
46 *Position = IFile->Position;
47 return EFI_SUCCESS;
48 }
49
50 /**
51
52 Set the file's position of the file.
53
54 @param FHand - The handle of file.
55 @param Position - The file's position of the file.
56
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.
60
61 **/
62 EFI_STATUS
63 EFIAPI
64 FatSetPosition (
65 IN EFI_FILE_PROTOCOL *FHand,
66 IN UINT64 Position
67 )
68 {
69 FAT_IFILE *IFile;
70 FAT_OFILE *OFile;
71
72 IFile = IFILE_FROM_FHAND (FHand);
73 OFile = IFile->OFile;
74
75 if (OFile->Error == EFI_NOT_FOUND) {
76 return EFI_DEVICE_ERROR;
77 }
78
79 FatWaitNonblockingTask (IFile);
80
81 //
82 // If this is a directory, we can only set back to position 0
83 //
84 if (OFile->ODir != NULL) {
85 if (Position != 0) {
86 //
87 // Reset current directory cursor;
88 //
89 return EFI_UNSUPPORTED;
90 }
91
92 FatResetODirCursor (OFile);
93 }
94
95 //
96 // Set the position
97 //
98 if (Position == (UINT64)-1) {
99 Position = OFile->FileSize;
100 }
101
102 //
103 // Set the position
104 //
105 IFile->Position = Position;
106 return EFI_SUCCESS;
107 }
108
109 /**
110
111 Get the file info from the open file of the IFile into Buffer.
112
113 @param IFile - The instance of the open file.
114 @param BufferSize - Size of Buffer.
115 @param Buffer - Buffer containing read data.
116
117 @retval EFI_SUCCESS - Get the file info successfully.
118 @retval other - An error occurred when operation the disk.
119
120 **/
121 EFI_STATUS
122 FatIFileReadDir (
123 IN FAT_IFILE *IFile,
124 IN OUT UINTN *BufferSize,
125 OUT VOID *Buffer
126 )
127 {
128 EFI_STATUS Status;
129 FAT_OFILE *OFile;
130 FAT_ODIR *ODir;
131 FAT_DIRENT *DirEnt;
132 UINT32 CurrentPos;
133
134 OFile = IFile->OFile;
135 ODir = OFile->ODir;
136 CurrentPos = ((UINT32)IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY);
137
138 //
139 // We need to relocate the directory
140 //
141 if (CurrentPos < ODir->CurrentPos) {
142 //
143 // The directory cursor has been modified by another IFile, we reset the cursor
144 //
145 FatResetODirCursor (OFile);
146 }
147
148 //
149 // We seek the next directory entry's position
150 //
151 do {
152 Status = FatGetNextDirEnt (OFile, &DirEnt);
153 if (EFI_ERROR (Status) || (DirEnt == NULL)) {
154 //
155 // Something error occurred or reach the end of directory,
156 // return 0 buffersize
157 //
158 *BufferSize = 0;
159 goto Done;
160 }
161 } while (ODir->CurrentPos <= CurrentPos);
162
163 Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer);
164
165 Done:
166 //
167 // Update IFile's Position
168 //
169 if (!EFI_ERROR (Status)) {
170 //
171 // Update IFile->Position, if everything is all right
172 //
173 CurrentPos = ODir->CurrentPos;
174 IFile->Position = CurrentPos * sizeof (FAT_DIRECTORY_ENTRY);
175 }
176
177 return Status;
178 }
179
180 /**
181
182 Get the file info from the open file of the IFile into Buffer.
183
184 @param FHand - The file handle to access.
185 @param IoMode - Indicate whether the access mode is reading or writing.
186 @param BufferSize - Size of Buffer.
187 @param Buffer - Buffer containing read data.
188 @param Token - A pointer to the token associated with the transaction.
189
190 @retval EFI_SUCCESS - Get the file info successfully.
191 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
192 @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
193 @retval EFI_WRITE_PROTECTED - The disk is write protect.
194 @retval EFI_ACCESS_DENIED - The file is read-only.
195 @return other - An error occurred when operating on the disk.
196
197 **/
198 EFI_STATUS
199 FatIFileAccess (
200 IN EFI_FILE_PROTOCOL *FHand,
201 IN IO_MODE IoMode,
202 IN OUT UINTN *BufferSize,
203 IN OUT VOID *Buffer,
204 IN EFI_FILE_IO_TOKEN *Token
205 )
206 {
207 EFI_STATUS Status;
208 FAT_IFILE *IFile;
209 FAT_OFILE *OFile;
210 FAT_VOLUME *Volume;
211 UINT64 EndPosition;
212 FAT_TASK *Task;
213
214 IFile = IFILE_FROM_FHAND (FHand);
215 OFile = IFile->OFile;
216 Volume = OFile->Volume;
217 Task = NULL;
218
219 //
220 // Write to a directory is unsupported
221 //
222 if ((OFile->ODir != NULL) && (IoMode == WriteData)) {
223 return EFI_UNSUPPORTED;
224 }
225
226 if (OFile->Error == EFI_NOT_FOUND) {
227 return EFI_DEVICE_ERROR;
228 }
229
230 if (IoMode == ReadData) {
231 //
232 // If position is at EOF, then return device error
233 //
234 if (IFile->Position > OFile->FileSize) {
235 return EFI_DEVICE_ERROR;
236 }
237 } else {
238 //
239 // Check if the we can write data
240 //
241 if (Volume->ReadOnly) {
242 return EFI_WRITE_PROTECTED;
243 }
244
245 if (IFile->ReadOnly) {
246 return EFI_ACCESS_DENIED;
247 }
248 }
249
250 if (Token == NULL) {
251 FatWaitNonblockingTask (IFile);
252 } else {
253 //
254 // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.
255 // But if it calls, the below check can avoid crash.
256 //
257 if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {
258 return EFI_UNSUPPORTED;
259 }
260
261 Task = FatCreateTask (IFile, Token);
262 if (Task == NULL) {
263 return EFI_OUT_OF_RESOURCES;
264 }
265 }
266
267 FatAcquireLock ();
268
269 Status = OFile->Error;
270 if (!EFI_ERROR (Status)) {
271 if (OFile->ODir != NULL) {
272 //
273 // Read a directory is supported
274 //
275 ASSERT (IoMode == ReadData);
276 Status = FatIFileReadDir (IFile, BufferSize, Buffer);
277 OFile = NULL;
278 } else {
279 //
280 // Access a file
281 //
282 EndPosition = IFile->Position + *BufferSize;
283 if (EndPosition > OFile->FileSize) {
284 //
285 // The position goes beyond the end of file
286 //
287 if (IoMode == ReadData) {
288 //
289 // Adjust the actual size read
290 //
291 *BufferSize -= (UINTN)EndPosition - OFile->FileSize;
292 } else {
293 //
294 // We expand the file size of OFile
295 //
296 Status = FatGrowEof (OFile, EndPosition);
297 if (EFI_ERROR (Status)) {
298 //
299 // Must update the file's info into the file's Directory Entry
300 // and then flush the dirty cache info into disk.
301 //
302 *BufferSize = 0;
303 FatOFileFlush (OFile);
304 OFile = NULL;
305 goto Done;
306 }
307
308 FatUpdateDirEntClusterSizeInfo (OFile);
309 }
310 }
311
312 Status = FatAccessOFile (OFile, IoMode, (UINTN)IFile->Position, BufferSize, Buffer, Task);
313 IFile->Position += *BufferSize;
314 }
315 }
316
317 if (Token != NULL) {
318 if (!EFI_ERROR (Status)) {
319 Status = FatQueueTask (IFile, Task);
320 } else {
321 FatDestroyTask (Task);
322 }
323 }
324
325 Done:
326 //
327 // On EFI_SUCCESS case, not calling FatCleanupVolume():
328 // 1) The Cache flush operation is avoided to enhance
329 // performance. Caller is responsible to call Flush() when necessary.
330 // 2) The volume dirty bit is probably set already, and is expected to be
331 // cleaned in subsequent Flush() or other operations.
332 // 3) Write operation doesn't affect OFile/IFile structure, so
333 // Reference checking is not necessary.
334 //
335 if (EFI_ERROR (Status)) {
336 Status = FatCleanupVolume (Volume, OFile, Status, NULL);
337 }
338
339 FatReleaseLock ();
340 return Status;
341 }
342
343 /**
344
345 Get the file info.
346
347 @param FHand - The handle of the file.
348 @param BufferSize - Size of Buffer.
349 @param Buffer - Buffer containing read data.
350
351
352 @retval EFI_SUCCESS - Get the file info successfully.
353 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
354 @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
355 @return other - An error occurred when operation the disk.
356
357 **/
358 EFI_STATUS
359 EFIAPI
360 FatRead (
361 IN EFI_FILE_PROTOCOL *FHand,
362 IN OUT UINTN *BufferSize,
363 OUT VOID *Buffer
364 )
365 {
366 return FatIFileAccess (FHand, ReadData, BufferSize, Buffer, NULL);
367 }
368
369 /**
370
371 Get the file info.
372
373 @param FHand - The handle of the file.
374 @param Token - A pointer to the token associated with the transaction.
375
376 @retval EFI_SUCCESS - Get the file info successfully.
377 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
378 @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
379 @return other - An error occurred when operation the disk.
380
381 **/
382 EFI_STATUS
383 EFIAPI
384 FatReadEx (
385 IN EFI_FILE_PROTOCOL *FHand,
386 IN OUT EFI_FILE_IO_TOKEN *Token
387 )
388 {
389 return FatIFileAccess (FHand, ReadData, &Token->BufferSize, Token->Buffer, Token);
390 }
391
392 /**
393
394 Write the content of buffer into files.
395
396 @param FHand - The handle of the file.
397 @param BufferSize - Size of Buffer.
398 @param Buffer - Buffer containing write data.
399
400 @retval EFI_SUCCESS - Set the file info successfully.
401 @retval EFI_WRITE_PROTECTED - The disk is write protect.
402 @retval EFI_ACCESS_DENIED - The file is read-only.
403 @retval EFI_DEVICE_ERROR - The OFile is not valid.
404 @retval EFI_UNSUPPORTED - The open file is not a file.
405 - The writing file size is larger than 4GB.
406 @return other - An error occurred when operation the disk.
407
408 **/
409 EFI_STATUS
410 EFIAPI
411 FatWrite (
412 IN EFI_FILE_PROTOCOL *FHand,
413 IN OUT UINTN *BufferSize,
414 IN VOID *Buffer
415 )
416 {
417 return FatIFileAccess (FHand, WriteData, BufferSize, Buffer, NULL);
418 }
419
420 /**
421
422 Get the file info.
423
424 @param FHand - The handle of the file.
425 @param Token - A pointer to the token associated with the transaction.
426
427 @retval EFI_SUCCESS - Get the file info successfully.
428 @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
429 @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
430 @return other - An error occurred when operation the disk.
431
432 **/
433 EFI_STATUS
434 EFIAPI
435 FatWriteEx (
436 IN EFI_FILE_PROTOCOL *FHand,
437 IN OUT EFI_FILE_IO_TOKEN *Token
438 )
439 {
440 return FatIFileAccess (FHand, WriteData, &Token->BufferSize, Token->Buffer, Token);
441 }
442
443 /**
444
445 This function reads data from a file or writes data to a file.
446 It uses OFile->PosRem to determine how much data can be accessed in one time.
447
448 @param OFile - The open file.
449 @param IoMode - Indicate whether the access mode is reading or writing.
450 @param Position - The position where data will be accessed.
451 @param DataBufferSize - Size of Buffer.
452 @param UserBuffer - Buffer containing data.
453 @param Task point to task instance.
454
455 @retval EFI_SUCCESS - Access the data successfully.
456 @return other - An error occurred when operating on the disk.
457
458 **/
459 EFI_STATUS
460 FatAccessOFile (
461 IN FAT_OFILE *OFile,
462 IN IO_MODE IoMode,
463 IN UINTN Position,
464 IN OUT UINTN *DataBufferSize,
465 IN OUT UINT8 *UserBuffer,
466 IN FAT_TASK *Task
467 )
468 {
469 FAT_VOLUME *Volume;
470 UINTN Len;
471 EFI_STATUS Status;
472 UINTN BufferSize;
473
474 BufferSize = *DataBufferSize;
475 Volume = OFile->Volume;
476 ASSERT_VOLUME_LOCKED (Volume);
477
478 Status = EFI_SUCCESS;
479 while (BufferSize > 0) {
480 //
481 // Seek the OFile to the file position
482 //
483 Status = FatOFilePosition (OFile, Position, BufferSize);
484 if (EFI_ERROR (Status)) {
485 break;
486 }
487
488 //
489 // Clip length to block run
490 //
491 Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize;
492
493 //
494 // Write the data
495 //
496 Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer, Task);
497 if (EFI_ERROR (Status)) {
498 break;
499 }
500
501 //
502 // Data was successfully accessed
503 //
504 Position += Len;
505 UserBuffer += Len;
506 BufferSize -= Len;
507 if (IoMode == WriteData) {
508 OFile->Dirty = TRUE;
509 OFile->Archive = TRUE;
510 }
511
512 //
513 // Make sure no outbound occurred
514 //
515 ASSERT (Position <= OFile->FileSize);
516 }
517
518 //
519 // Update the number of bytes accessed
520 //
521 *DataBufferSize -= BufferSize;
522 return Status;
523 }
524
525 /**
526
527 Expand OFile by appending zero bytes at the end of OFile.
528
529 @param OFile - The open file.
530 @param ExpandedSize - The number of zero bytes appended at the end of the file.
531
532 @retval EFI_SUCCESS - The file is expanded successfully.
533 @return other - An error occurred when expanding file.
534
535 **/
536 EFI_STATUS
537 FatExpandOFile (
538 IN FAT_OFILE *OFile,
539 IN UINT64 ExpandedSize
540 )
541 {
542 EFI_STATUS Status;
543 UINTN WritePos;
544
545 WritePos = OFile->FileSize;
546 Status = FatGrowEof (OFile, ExpandedSize);
547 if (!EFI_ERROR (Status)) {
548 Status = FatWriteZeroPool (OFile, WritePos);
549 }
550
551 return Status;
552 }
553
554 /**
555
556 Write zero pool from the WritePos to the end of OFile.
557
558 @param OFile - The open file to write zero pool.
559 @param WritePos - The number of zero bytes written.
560
561 @retval EFI_SUCCESS - Write the zero pool successfully.
562 @retval EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation.
563 @return other - An error occurred when writing disk.
564
565 **/
566 EFI_STATUS
567 FatWriteZeroPool (
568 IN FAT_OFILE *OFile,
569 IN UINTN WritePos
570 )
571 {
572 EFI_STATUS Status;
573 VOID *ZeroBuffer;
574 UINTN AppendedSize;
575 UINTN BufferSize;
576 UINTN WriteSize;
577
578 AppendedSize = OFile->FileSize - WritePos;
579 BufferSize = AppendedSize;
580 if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) {
581 //
582 // If the appended size is larger, maybe we can not allocate the whole
583 // memory once. So if the growed size is larger than 10M, we just
584 // allocate 10M memory (one healthy system should have 10M available
585 // memory), and then write the zerobuffer to the file several times.
586 //
587 BufferSize = FAT_MAX_ALLOCATE_SIZE;
588 }
589
590 ZeroBuffer = AllocateZeroPool (BufferSize);
591 if (ZeroBuffer == NULL) {
592 return EFI_OUT_OF_RESOURCES;
593 }
594
595 do {
596 WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN)AppendedSize;
597 AppendedSize -= WriteSize;
598 Status = FatAccessOFile (OFile, WriteData, WritePos, &WriteSize, ZeroBuffer, NULL);
599 if (EFI_ERROR (Status)) {
600 break;
601 }
602
603 WritePos += WriteSize;
604 } while (AppendedSize > 0);
605
606 FreePool (ZeroBuffer);
607 return Status;
608 }
609
610 /**
611
612 Truncate the OFile to smaller file size.
613
614 @param OFile - The open file.
615 @param TruncatedSize - The new file size.
616
617 @retval EFI_SUCCESS - The file is truncated successfully.
618 @return other - An error occurred when truncating file.
619
620 **/
621 EFI_STATUS
622 FatTruncateOFile (
623 IN FAT_OFILE *OFile,
624 IN UINTN TruncatedSize
625 )
626 {
627 OFile->FileSize = TruncatedSize;
628 return FatShrinkEof (OFile);
629 }