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