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