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