]> git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/EnhancedFatDxe/ReadWrite.c
Merge 2-clause BSD licensed FatPkg
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / ReadWrite.c
1 /*++
2
3 Copyright (c) 2005 - 2015, 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 //
254 // Write to a directory is unsupported
255 //
256 if ((OFile->ODir != NULL) && (IoMode == WRITE_DATA)) {
257 return EFI_UNSUPPORTED;
258 }
259
260 if (OFile->Error == EFI_NOT_FOUND) {
261 return EFI_DEVICE_ERROR;
262 }
263
264 if (IoMode == READ_DATA) {
265 //
266 // If position is at EOF, then return device error
267 //
268 if (IFile->Position > OFile->FileSize) {
269 return EFI_DEVICE_ERROR;
270 }
271 } else {
272 //
273 // Check if the we can write data
274 //
275 if (Volume->ReadOnly) {
276 return EFI_WRITE_PROTECTED;
277 }
278
279 if (IFile->ReadOnly) {
280 return EFI_ACCESS_DENIED;
281 }
282 }
283
284 if (Token == NULL) {
285 FatWaitNonblockingTask (IFile);
286 } else {
287 //
288 // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.
289 // But if it calls, the below check can avoid crash.
290 //
291 if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {
292 return EFI_UNSUPPORTED;
293 }
294 Task = FatCreateTask (IFile, Token);
295 if (Task == NULL) {
296 return EFI_OUT_OF_RESOURCES;
297 }
298 }
299
300 FatAcquireLock ();
301
302 Status = OFile->Error;
303 if (!EFI_ERROR (Status)) {
304 if (OFile->ODir != NULL) {
305 //
306 // Read a directory is supported
307 //
308 ASSERT (IoMode == READ_DATA);
309 Status = FatIFileReadDir (IFile, BufferSize, Buffer);
310 OFile = NULL;
311 } else {
312 //
313 // Access a file
314 //
315 EndPosition = IFile->Position + *BufferSize;
316 if (EndPosition > OFile->FileSize) {
317 //
318 // The position goes beyond the end of file
319 //
320 if (IoMode == READ_DATA) {
321 //
322 // Adjust the actual size read
323 //
324 *BufferSize -= (UINTN) EndPosition - OFile->FileSize;
325 } else {
326 //
327 // We expand the file size of OFile
328 //
329 Status = FatGrowEof (OFile, EndPosition);
330 if (EFI_ERROR (Status)) {
331 //
332 // Must update the file's info into the file's Directory Entry
333 // and then flush the dirty cache info into disk.
334 //
335 *BufferSize = 0;
336 FatOFileFlush (OFile);
337 OFile = NULL;
338 goto Done;
339 }
340
341 FatUpdateDirEntClusterSizeInfo (OFile);
342 }
343 }
344
345 Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer, Task);
346 IFile->Position += *BufferSize;
347 }
348 }
349
350 if (Token != NULL) {
351 if (!EFI_ERROR (Status)) {
352 Status = FatQueueTask (IFile, Task);
353 } else {
354 FatDestroyTask (Task);
355 }
356 }
357
358 Done:
359 //
360 // On EFI_SUCCESS case, not calling FatCleanupVolume():
361 // 1) The Cache flush operation is avoided to enhance
362 // performance. Caller is responsible to call Flush() when necessary.
363 // 2) The volume dirty bit is probably set already, and is expected to be
364 // cleaned in subsequent Flush() or other operations.
365 // 3) Write operation doesn't affect OFile/IFile structure, so
366 // Reference checking is not necessary.
367 //
368 if (EFI_ERROR (Status)) {
369 Status = FatCleanupVolume (Volume, OFile, Status, NULL);
370 }
371
372 FatReleaseLock ();
373 return Status;
374 }
375
376 EFI_STATUS
377 EFIAPI
378 FatRead (
379 IN EFI_FILE_PROTOCOL *FHand,
380 IN OUT UINTN *BufferSize,
381 OUT VOID *Buffer
382 )
383 /*++
384
385 Routine Description:
386
387 Get the file info.
388
389 Arguments:
390
391 FHand - The handle of the file.
392 BufferSize - Size of Buffer.
393 Buffer - Buffer containing read data.
394
395 Returns:
396
397 EFI_SUCCESS - Get the file info successfully.
398 EFI_DEVICE_ERROR - Can not find the OFile for the file.
399 EFI_VOLUME_CORRUPTED - The file type of open file is error.
400 other - An error occurred when operation the disk.
401
402 --*/
403 {
404 return FatIFileAccess (FHand, READ_DATA, BufferSize, Buffer, NULL);
405 }
406
407 EFI_STATUS
408 EFIAPI
409 FatReadEx (
410 IN EFI_FILE_PROTOCOL *FHand,
411 IN OUT EFI_FILE_IO_TOKEN *Token
412 )
413 /*++
414
415 Routine Description:
416
417 Get the file info.
418
419 Arguments:
420
421 FHand - The handle of the file.
422 Token - A pointer to the token associated with the transaction.
423
424 Returns:
425
426 EFI_SUCCESS - Get the file info successfully.
427 EFI_DEVICE_ERROR - Can not find the OFile for the file.
428 EFI_VOLUME_CORRUPTED - The file type of open file is error.
429 other - An error occurred when operation the disk.
430
431 --*/
432 {
433 return FatIFileAccess (FHand, READ_DATA, &Token->BufferSize, Token->Buffer, Token);
434 }
435
436 EFI_STATUS
437 EFIAPI
438 FatWrite (
439 IN EFI_FILE_PROTOCOL *FHand,
440 IN OUT UINTN *BufferSize,
441 IN VOID *Buffer
442 )
443 /*++
444
445 Routine Description:
446
447 Write the content of buffer into files.
448
449 Arguments:
450
451 FHand - The handle of the file.
452 BufferSize - Size of Buffer.
453 Buffer - Buffer containing write data.
454
455 Returns:
456
457 EFI_SUCCESS - Set the file info successfully.
458 EFI_WRITE_PROTECTED - The disk is write protect.
459 EFI_ACCESS_DENIED - The file is read-only.
460 EFI_DEVICE_ERROR - The OFile is not valid.
461 EFI_UNSUPPORTED - The open file is not a file.
462 - The writing file size is larger than 4GB.
463 other - An error occurred when operation the disk.
464
465 --*/
466 {
467 return FatIFileAccess (FHand, WRITE_DATA, BufferSize, Buffer, NULL);
468 }
469
470 EFI_STATUS
471 EFIAPI
472 FatWriteEx (
473 IN EFI_FILE_PROTOCOL *FHand,
474 IN OUT EFI_FILE_IO_TOKEN *Token
475 )
476 /*++
477
478 Routine Description:
479
480 Get the file info.
481
482 Arguments:
483
484 FHand - The handle of the file.
485 Token - A pointer to the token associated with the transaction.
486
487 Returns:
488
489 EFI_SUCCESS - Get the file info successfully.
490 EFI_DEVICE_ERROR - Can not find the OFile for the file.
491 EFI_VOLUME_CORRUPTED - The file type of open file is error.
492 other - An error occurred when operation the disk.
493
494 --*/
495 {
496 return FatIFileAccess (FHand, WRITE_DATA, &Token->BufferSize, Token->Buffer, Token);
497 }
498
499 EFI_STATUS
500 FatAccessOFile (
501 IN FAT_OFILE *OFile,
502 IN IO_MODE IoMode,
503 IN UINTN Position,
504 IN OUT UINTN *DataBufferSize,
505 IN OUT UINT8 *UserBuffer,
506 IN FAT_TASK *Task
507 )
508 /*++
509
510 Routine Description:
511
512 This function reads data from a file or writes data to a file.
513 It uses OFile->PosRem to determine how much data can be accessed in one time.
514
515 Arguments:
516
517 OFile - The open file.
518 IoMode - Indicate whether the access mode is reading or writing.
519 Position - The position where data will be accessed.
520 DataBufferSize - Size of Buffer.
521 UserBuffer - Buffer containing data.
522
523 Returns:
524
525 EFI_SUCCESS - Access the data successfully.
526 other - An error occurred when operating on the disk.
527
528 --*/
529 {
530 FAT_VOLUME *Volume;
531 UINTN Len;
532 EFI_STATUS Status;
533 UINTN BufferSize;
534
535 BufferSize = *DataBufferSize;
536 Volume = OFile->Volume;
537 ASSERT_VOLUME_LOCKED (Volume);
538
539 Status = EFI_SUCCESS;
540 while (BufferSize > 0) {
541 //
542 // Seek the OFile to the file position
543 //
544 Status = FatOFilePosition (OFile, Position, BufferSize);
545 if (EFI_ERROR (Status)) {
546 break;
547 }
548 //
549 // Clip length to block run
550 //
551 Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize;
552
553 //
554 // Write the data
555 //
556 Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer, Task);
557 if (EFI_ERROR (Status)) {
558 break;
559 }
560 //
561 // Data was successfully accessed
562 //
563 Position += Len;
564 UserBuffer += Len;
565 BufferSize -= Len;
566 if (IoMode == WRITE_DATA) {
567 OFile->Dirty = TRUE;
568 OFile->Archive = TRUE;
569 }
570 //
571 // Make sure no outbound occurred
572 //
573 ASSERT (Position <= OFile->FileSize);
574 }
575 //
576 // Update the number of bytes accessed
577 //
578 *DataBufferSize -= BufferSize;
579 return Status;
580 }
581
582 EFI_STATUS
583 FatExpandOFile (
584 IN FAT_OFILE *OFile,
585 IN UINT64 ExpandedSize
586 )
587 /*++
588
589 Routine Description:
590
591 Expand OFile by appending zero bytes at the end of OFile.
592
593 Arguments:
594
595 OFile - The open file.
596 ExpandedSize - The number of zero bytes appended at the end of the file.
597
598 Returns:
599
600 EFI_SUCCESS - The file is expanded successfully.
601 other - An error occurred when expanding file.
602
603 --*/
604 {
605 EFI_STATUS Status;
606 UINTN WritePos;
607
608 WritePos = OFile->FileSize;
609 Status = FatGrowEof (OFile, ExpandedSize);
610 if (!EFI_ERROR (Status)) {
611 Status = FatWriteZeroPool (OFile, WritePos);
612 }
613
614 return Status;
615 }
616
617 EFI_STATUS
618 FatWriteZeroPool (
619 IN FAT_OFILE *OFile,
620 IN UINTN WritePos
621 )
622 /*++
623
624 Routine Description:
625
626 Write zero pool from the WritePos to the end of OFile.
627
628 Arguments:
629
630 OFile - The open file to write zero pool.
631 WritePos - The number of zero bytes written.
632
633 Returns:
634
635 EFI_SUCCESS - Write the zero pool successfully.
636 EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation.
637 other - An error occurred when writing disk.
638
639 --*/
640 {
641 EFI_STATUS Status;
642 VOID *ZeroBuffer;
643 UINTN AppendedSize;
644 UINTN BufferSize;
645 UINTN WriteSize;
646
647 AppendedSize = OFile->FileSize - WritePos;
648 BufferSize = AppendedSize;
649 if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) {
650 //
651 // If the appended size is larger, maybe we can not allocate the whole
652 // memory once. So if the growed size is larger than 10M, we just
653 // allocate 10M memory (one healthy system should have 10M available
654 // memory), and then write the zerobuffer to the file several times.
655 //
656 BufferSize = FAT_MAX_ALLOCATE_SIZE;
657 }
658
659 ZeroBuffer = AllocateZeroPool (BufferSize);
660 if (ZeroBuffer == NULL) {
661 return EFI_OUT_OF_RESOURCES;
662 }
663
664 do {
665 WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize;
666 AppendedSize -= WriteSize;
667 Status = FatAccessOFile (OFile, WRITE_DATA, WritePos, &WriteSize, ZeroBuffer, NULL);
668 if (EFI_ERROR (Status)) {
669 break;
670 }
671
672 WritePos += WriteSize;
673 } while (AppendedSize > 0);
674
675 FreePool (ZeroBuffer);
676 return Status;
677 }
678
679 EFI_STATUS
680 FatTruncateOFile (
681 IN FAT_OFILE *OFile,
682 IN UINTN TruncatedSize
683 )
684 /*++
685
686 Routine Description:
687
688 Truncate the OFile to smaller file size.
689
690 Arguments:
691
692 OFile - The open file.
693 TruncatedSize - The new file size.
694
695 Returns:
696
697 EFI_SUCCESS - The file is truncated successfully.
698 other - An error occurred when truncating file.
699
700 --*/
701 {
702 OFile->FileSize = TruncatedSize;
703 return FatShrinkEof (OFile);
704 }