]> git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/EnhancedFatDxe/ReadWrite.c
Fix a warning issue with ARMCC.
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / ReadWrite.c
1 /*++
2
3 Copyright (c) 2005 - 2009, Intel Corporation
4 All rights reserved. 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 // If this is a directory, we can only set back to position 0
106 //
107 if (OFile->ODir != NULL) {
108 if (Position != 0) {
109 //
110 // Reset current directory cursor;
111 //
112 return EFI_UNSUPPORTED;
113 }
114
115 FatResetODirCursor (OFile);
116 }
117 //
118 // Set the position
119 //
120 if (Position == (UINT64)-1) {
121 Position = OFile->FileSize;
122 }
123 //
124 // Set the position
125 //
126 IFile->Position = Position;
127 return EFI_SUCCESS;
128 }
129
130 EFI_STATUS
131 FatIFileReadDir (
132 IN FAT_IFILE *IFile,
133 IN OUT UINTN *BufferSize,
134 OUT VOID *Buffer
135 )
136 /*++
137
138 Routine Description:
139
140 Get the file info from the open file of the IFile into Buffer.
141
142 Arguments:
143
144 IFile - The instance of the open file.
145 BufferSize - Size of Buffer.
146 Buffer - Buffer containing read data.
147
148 Returns:
149
150 EFI_SUCCESS - Get the file info successfully.
151 other - An error occurred when operation the disk.
152
153 --*/
154 {
155 EFI_STATUS Status;
156 FAT_OFILE *OFile;
157 FAT_ODIR *ODir;
158 FAT_DIRENT *DirEnt;
159 UINT32 CurrentPos;
160
161 OFile = IFile->OFile;
162 ODir = OFile->ODir;
163 CurrentPos = ((UINT32) IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY);
164
165 //
166 // We need to relocate the directory
167 //
168 if (CurrentPos < ODir->CurrentPos) {
169 //
170 // The directory cursor has been modified by another IFile, we reset the cursor
171 //
172 FatResetODirCursor (OFile);
173 }
174 //
175 // We seek the next directory entry's position
176 //
177 do {
178 Status = FatGetNextDirEnt (OFile, &DirEnt);
179 if (EFI_ERROR (Status) || DirEnt == NULL) {
180 //
181 // Something error occurred or reach the end of directory,
182 // return 0 buffersize
183 //
184 *BufferSize = 0;
185 goto Done;
186 }
187 } while (ODir->CurrentPos <= CurrentPos);
188 Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer);
189
190 Done:
191 //
192 // Update IFile's Position
193 //
194 if (!EFI_ERROR (Status)) {
195 //
196 // Update IFile->Position, if everything is all right
197 //
198 CurrentPos = ODir->CurrentPos;
199 IFile->Position = (UINT64) (CurrentPos * sizeof (FAT_DIRECTORY_ENTRY));
200 }
201
202 return Status;
203 }
204
205 EFI_STATUS
206 FatIFileAccess (
207 IN EFI_FILE_PROTOCOL *FHand,
208 IN IO_MODE IoMode,
209 IN OUT UINTN *BufferSize,
210 IN OUT VOID *Buffer
211 )
212 /*++
213
214 Routine Description:
215
216 Get the file info from the open file of the IFile into Buffer.
217
218 Arguments:
219
220 FHand - The file handle to access.
221 IoMode - Indicate whether the access mode is reading or writing.
222 BufferSize - Size of Buffer.
223 Buffer - Buffer containing read data.
224
225 Returns:
226
227 EFI_SUCCESS - Get the file info successfully.
228 EFI_DEVICE_ERROR - Can not find the OFile for the file.
229 EFI_VOLUME_CORRUPTED - The file type of open file is error.
230 EFI_WRITE_PROTECTED - The disk is write protect.
231 EFI_ACCESS_DENIED - The file is read-only.
232 other - An error occurred when operating on the disk.
233
234 --*/
235 {
236 EFI_STATUS Status;
237 FAT_IFILE *IFile;
238 FAT_OFILE *OFile;
239 FAT_VOLUME *Volume;
240 UINT64 EndPosition;
241
242 IFile = IFILE_FROM_FHAND (FHand);
243 OFile = IFile->OFile;
244 Volume = OFile->Volume;
245
246 if (OFile->Error == EFI_NOT_FOUND) {
247 return EFI_DEVICE_ERROR;
248 }
249
250 if (IoMode == READ_DATA) {
251 //
252 // If position is at EOF, then return device error
253 //
254 if (IFile->Position > OFile->FileSize) {
255 return EFI_DEVICE_ERROR;
256 }
257 } else {
258 //
259 // Check if the we can write data
260 //
261 if (Volume->ReadOnly) {
262 return EFI_WRITE_PROTECTED;
263 }
264
265 if (IFile->ReadOnly) {
266 return EFI_ACCESS_DENIED;
267 }
268 }
269
270 FatAcquireLock ();
271
272 Status = OFile->Error;
273 if (!EFI_ERROR (Status)) {
274 if (OFile->ODir != NULL) {
275 //
276 // Access a directory
277 //
278 Status = EFI_UNSUPPORTED;
279 if (IoMode == READ_DATA) {
280 //
281 // Read a directory is supported
282 //
283 Status = FatIFileReadDir (IFile, BufferSize, Buffer);
284 }
285
286 OFile = NULL;
287 } else {
288 //
289 // Access a file
290 //
291 EndPosition = IFile->Position + *BufferSize;
292 if (EndPosition > OFile->FileSize) {
293 //
294 // The position goes beyond the end of file
295 //
296 if (IoMode == READ_DATA) {
297 //
298 // Adjust the actual size read
299 //
300 *BufferSize -= (UINTN) EndPosition - OFile->FileSize;
301 } else {
302 //
303 // We expand the file size of OFile
304 //
305 Status = FatGrowEof (OFile, EndPosition);
306 if (EFI_ERROR (Status)) {
307 //
308 // Must update the file's info into the file's Directory Entry
309 // and then flush the dirty cache info into disk.
310 //
311 *BufferSize = 0;
312 FatOFileFlush (OFile);
313 OFile = NULL;
314 goto Done;
315 }
316
317 FatUpdateDirEntClusterSizeInfo (OFile);
318 }
319 }
320
321 Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer);
322 IFile->Position += *BufferSize;
323 }
324 }
325
326 Done:
327 if (EFI_ERROR (Status)) {
328 Status = FatCleanupVolume (Volume, OFile, Status);
329 }
330 //
331 // On EFI_SUCCESS case, not calling FatCleanupVolume():
332 // 1) The Cache flush operation is avoided to enhance
333 // performance. Caller is responsible to call Flush() when necessary.
334 // 2) The volume dirty bit is probably set already, and is expected to be
335 // cleaned in subsequent Flush() or other operations.
336 // 3) Write operation doesn't affect OFile/IFile structure, so
337 // Reference checking is not necessary.
338 //
339 FatReleaseLock ();
340 return Status;
341 }
342
343 EFI_STATUS
344 EFIAPI
345 FatRead (
346 IN EFI_FILE_PROTOCOL *FHand,
347 IN OUT UINTN *BufferSize,
348 OUT VOID *Buffer
349 )
350 /*++
351
352 Routine Description:
353
354 Get the file info.
355
356 Arguments:
357
358 FHand - The handle of the file.
359 BufferSize - Size of Buffer.
360 Buffer - Buffer containing read data.
361
362 Returns:
363
364 EFI_SUCCESS - Get the file info successfully.
365 EFI_DEVICE_ERROR - Can not find the OFile for the file.
366 EFI_VOLUME_CORRUPTED - The file type of open file is error.
367 other - An error occurred when operation the disk.
368
369 --*/
370 {
371 return FatIFileAccess (FHand, READ_DATA, BufferSize, Buffer);
372 }
373
374 EFI_STATUS
375 EFIAPI
376 FatWrite (
377 IN EFI_FILE_PROTOCOL *FHand,
378 IN OUT UINTN *BufferSize,
379 IN VOID *Buffer
380 )
381 /*++
382
383 Routine Description:
384
385 Write the content of buffer into files.
386
387 Arguments:
388
389 FHand - The handle of the file.
390 BufferSize - Size of Buffer.
391 Buffer - Buffer containing write data.
392
393 Returns:
394
395 EFI_SUCCESS - Set the file info successfully.
396 EFI_WRITE_PROTECTED - The disk is write protect.
397 EFI_ACCESS_DENIED - The file is read-only.
398 EFI_DEVICE_ERROR - The OFile is not valid.
399 EFI_UNSUPPORTED - The open file is not a file.
400 - The writing file size is larger than 4GB.
401 other - An error occurred when operation the disk.
402
403 --*/
404 {
405 return FatIFileAccess (FHand, WRITE_DATA, BufferSize, Buffer);
406 }
407
408 EFI_STATUS
409 FatAccessOFile (
410 IN FAT_OFILE *OFile,
411 IN IO_MODE IoMode,
412 IN UINTN Position,
413 IN OUT UINTN *DataBufferSize,
414 IN OUT UINT8 *UserBuffer
415 )
416 /*++
417
418 Routine Description:
419
420 This function reads data from a file or writes data to a file.
421 It uses OFile->PosRem to determine how much data can be accessed in one time.
422
423 Arguments:
424
425 OFile - The open file.
426 IoMode - Indicate whether the access mode is reading or writing.
427 Position - The position where data will be accessed.
428 DataBufferSize - Size of Buffer.
429 UserBuffer - Buffer containing data.
430
431 Returns:
432
433 EFI_SUCCESS - Access the data successfully.
434 other - An error occurred when operating on the disk.
435
436 --*/
437 {
438 FAT_VOLUME *Volume;
439 UINTN Len;
440 EFI_STATUS Status;
441 UINTN BufferSize;
442
443 BufferSize = *DataBufferSize;
444 Volume = OFile->Volume;
445 ASSERT_VOLUME_LOCKED (Volume);
446
447 Status = EFI_SUCCESS;
448 while (BufferSize > 0) {
449 //
450 // Seek the OFile to the file position
451 //
452 Status = FatOFilePosition (OFile, Position, BufferSize);
453 if (EFI_ERROR (Status)) {
454 break;
455 }
456 //
457 // Clip length to block run
458 //
459 Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize;
460
461 //
462 // Write the data
463 //
464 Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer);
465 if (EFI_ERROR (Status)) {
466 break;
467 }
468 //
469 // Data was successfully accessed
470 //
471 Position += Len;
472 UserBuffer += Len;
473 BufferSize -= Len;
474 if (IoMode == WRITE_DATA) {
475 OFile->Dirty = TRUE;
476 OFile->Archive = TRUE;
477 }
478 //
479 // Make sure no outbound occurred
480 //
481 ASSERT (Position <= OFile->FileSize);
482 }
483 //
484 // Update the number of bytes accessed
485 //
486 *DataBufferSize -= BufferSize;
487 return Status;
488 }
489
490 EFI_STATUS
491 FatExpandOFile (
492 IN FAT_OFILE *OFile,
493 IN UINT64 ExpandedSize
494 )
495 /*++
496
497 Routine Description:
498
499 Expand OFile by appending zero bytes at the end of OFile.
500
501 Arguments:
502
503 OFile - The open file.
504 ExpandedSize - The number of zero bytes appended at the end of the file.
505
506 Returns:
507
508 EFI_SUCCESS - The file is expanded successfully.
509 other - An error occurred when expanding file.
510
511 --*/
512 {
513 EFI_STATUS Status;
514 UINTN WritePos;
515
516 WritePos = OFile->FileSize;
517 Status = FatGrowEof (OFile, ExpandedSize);
518 if (!EFI_ERROR (Status)) {
519 Status = FatWriteZeroPool (OFile, WritePos);
520 }
521
522 return Status;
523 }
524
525 EFI_STATUS
526 FatWriteZeroPool (
527 IN FAT_OFILE *OFile,
528 IN UINTN WritePos
529 )
530 /*++
531
532 Routine Description:
533
534 Write zero pool from the WritePos to the end of OFile.
535
536 Arguments:
537
538 OFile - The open file to write zero pool.
539 WritePos - The number of zero bytes written.
540
541 Returns:
542
543 EFI_SUCCESS - Write the zero pool successfully.
544 EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation.
545 other - An error occurred when writing disk.
546
547 --*/
548 {
549 EFI_STATUS Status;
550 VOID *ZeroBuffer;
551 UINTN AppendedSize;
552 UINTN BufferSize;
553 UINTN WriteSize;
554
555 AppendedSize = OFile->FileSize - WritePos;
556 BufferSize = AppendedSize;
557 if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) {
558 //
559 // If the appended size is larger, maybe we can not allocate the whole
560 // memory once. So if the growed size is larger than 10M, we just
561 // allocate 10M memory (one healthy system should have 10M available
562 // memory), and then write the zerobuffer to the file several times.
563 //
564 BufferSize = FAT_MAX_ALLOCATE_SIZE;
565 }
566
567 ZeroBuffer = AllocateZeroPool (BufferSize);
568 if (ZeroBuffer == NULL) {
569 return EFI_OUT_OF_RESOURCES;
570 }
571
572 do {
573 WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize;
574 AppendedSize -= WriteSize;
575 Status = FatAccessOFile (OFile, WRITE_DATA, WritePos, &WriteSize, ZeroBuffer);
576 if (EFI_ERROR (Status)) {
577 break;
578 }
579
580 WritePos += WriteSize;
581 } while (AppendedSize > 0);
582
583 FreePool (ZeroBuffer);
584 return Status;
585 }
586
587 EFI_STATUS
588 FatTruncateOFile (
589 IN FAT_OFILE *OFile,
590 IN UINTN TruncatedSize
591 )
592 /*++
593
594 Routine Description:
595
596 Truncate the OFile to smaller file size.
597
598 Arguments:
599
600 OFile - The open file.
601 TruncatedSize - The new file size.
602
603 Returns:
604
605 EFI_SUCCESS - The file is truncated successfully.
606 other - An error occurred when truncating file.
607
608 --*/
609 {
610 OFile->FileSize = TruncatedSize;
611 return FatShrinkEof (OFile);
612 }