VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/FatPkg/EnhancedFatDxe/ReadWrite.c@ 77662

Last change on this file since 77662 was 77662, checked in by vboxsync, 6 years ago

EFI: First step in UDK2018 merge. Does not build yet.

  • Property svn:eol-style set to native
File size: 16.0 KB
Line 
1/** @file
2 Functions that perform file read/write.
3
4Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials are licensed and made available
6under the terms and conditions of the BSD License which accompanies this
7distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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**/
31EFI_STATUS
32EFIAPI
33FatGetPosition (
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**/
68EFI_STATUS
69EFIAPI
70FatSetPosition (
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**/
125EFI_STATUS
126FatIFileReadDir (
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
167Done:
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 = 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**/
200EFI_STATUS
201FatIFileAccess (
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
326Done:
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**/
359EFI_STATUS
360EFIAPI
361FatRead (
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**/
383EFI_STATUS
384EFIAPI
385FatReadEx (
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**/
410EFI_STATUS
411EFIAPI
412FatWrite (
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**/
434EFI_STATUS
435EFIAPI
436FatWriteEx (
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**/
460EFI_STATUS
461FatAccessOFile (
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**/
533EFI_STATUS
534FatExpandOFile (
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**/
563EFI_STATUS
564FatWriteZeroPool (
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**/
618EFI_STATUS
619FatTruncateOFile (
620 IN FAT_OFILE *OFile,
621 IN UINTN TruncatedSize
622 )
623{
624 OFile->FileSize = TruncatedSize;
625 return FatShrinkEof (OFile);
626}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette