]> git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/EnhancedFatDxe/Misc.c
FatPkg/EnhancedFatDxe: Make the variable name follow rule
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / Misc.c
1 /*++
2
3 Copyright (c) 2005 - 2013, 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 Misc.c
16
17 Abstract:
18
19 Miscellaneous functions
20
21 Revision History
22
23 --*/
24
25 #include "Fat.h"
26 UINT8 mMonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
27
28 FAT_TASK *
29 FatCreateTask (
30 FAT_IFILE *IFile,
31 EFI_FILE_IO_TOKEN *Token
32 )
33 /*++
34
35 Routine Description:
36
37 Create the task
38
39 Arguments:
40
41 IFile - The instance of the open file.
42 Token - A pointer to the token associated with the transaction.
43
44 Return:
45 FAT_TASK * - Return the task instance.
46 **/
47 {
48 FAT_TASK *Task;
49
50 Task = AllocateZeroPool (sizeof (*Task));
51 if (Task != NULL) {
52 Task->Signature = FAT_TASK_SIGNATURE;
53 Task->IFile = IFile;
54 Task->FileIoToken = Token;
55 InitializeListHead (&Task->Subtasks);
56 InitializeListHead (&Task->Link);
57 }
58 return Task;
59 }
60
61 VOID
62 FatDestroyTask (
63 FAT_TASK *Task
64 )
65 /*++
66
67 Routine Description:
68
69 Destroy the task
70
71 Arguments:
72
73 Task - The task to be destroyed.
74 **/
75 {
76 LIST_ENTRY *Link;
77 FAT_SUBTASK *Subtask;
78
79 Link = GetFirstNode (&Task->Subtasks);
80 while (!IsNull (&Task->Subtasks, Link)) {
81 Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
82 Link = FatDestroySubtask (Subtask);
83 }
84 FreePool (Task);
85 }
86
87 VOID
88 FatWaitNonblockingTask (
89 FAT_IFILE *IFile
90 )
91 /*++
92
93 Routine Description:
94
95 Wait all non-blocking requests complete.
96
97 Arguments:
98
99 IFile - The instance of the open file.
100 **/
101 {
102 BOOLEAN TaskQueueEmpty;
103
104 do {
105 EfiAcquireLock (&FatTaskLock);
106 TaskQueueEmpty = IsListEmpty (&IFile->Tasks);
107 EfiReleaseLock (&FatTaskLock);
108 } while (!TaskQueueEmpty);
109 }
110
111 LIST_ENTRY *
112 FatDestroySubtask (
113 FAT_SUBTASK *Subtask
114 )
115 /*++
116
117 Routine Description:
118
119 Remove the subtask from subtask list.
120
121 Arguments:
122
123 Subtask - The subtask to be removed.
124
125 Returns:
126
127 LIST_ENTRY * - The next node in the list.
128
129 --*/
130 {
131 LIST_ENTRY *Link;
132
133 gBS->CloseEvent (Subtask->DiskIo2Token.Event);
134
135 Link = RemoveEntryList (&Subtask->Link);
136 FreePool (Subtask);
137
138 return Link;
139 }
140
141 EFI_STATUS
142 FatQueueTask (
143 IN FAT_IFILE *IFile,
144 IN FAT_TASK *Task
145 )
146 /*++
147
148 Routine Description:
149
150 Execute the task
151
152 Arguments:
153
154 IFile - The instance of the open file.
155 Task - The task to be executed.
156
157 Returns:
158
159 EFI_SUCCESS - The task was executed sucessfully.
160 other - An error occurred when executing the task.
161
162 --*/
163 {
164 EFI_STATUS Status;
165 LIST_ENTRY *Link;
166 FAT_SUBTASK *Subtask;
167
168 //
169 // Sometimes the Task doesn't contain any subtasks, signal the event directly.
170 //
171 if (IsListEmpty (&Task->Subtasks)) {
172 Task->FileIoToken->Status = EFI_SUCCESS;
173 gBS->SignalEvent (Task->FileIoToken->Event);
174 FreePool (Task);
175 return EFI_SUCCESS;
176 }
177
178 EfiAcquireLock (&FatTaskLock);
179 InsertTailList (&IFile->Tasks, &Task->Link);
180 EfiReleaseLock (&FatTaskLock);
181
182 Status = EFI_SUCCESS;
183 for ( Link = GetFirstNode (&Task->Subtasks)
184 ; !IsNull (&Task->Subtasks, Link)
185 ; Link = GetNextNode (&Task->Subtasks, Link)
186 ) {
187 Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
188 if (Subtask->Write) {
189
190 Status = IFile->OFile->Volume->DiskIo2->WriteDiskEx (
191 IFile->OFile->Volume->DiskIo2,
192 IFile->OFile->Volume->MediaId,
193 Subtask->Offset,
194 &Subtask->DiskIo2Token,
195 Subtask->BufferSize,
196 Subtask->Buffer
197 );
198 } else {
199 Status = IFile->OFile->Volume->DiskIo2->ReadDiskEx (
200 IFile->OFile->Volume->DiskIo2,
201 IFile->OFile->Volume->MediaId,
202 Subtask->Offset,
203 &Subtask->DiskIo2Token,
204 Subtask->BufferSize,
205 Subtask->Buffer
206 );
207 }
208 if (EFI_ERROR (Status)) {
209 break;
210 }
211 }
212
213 if (EFI_ERROR (Status)) {
214 EfiAcquireLock (&FatTaskLock);
215 //
216 // Remove all the remaining subtasks when failure.
217 // We shouldn't remove all the tasks because the non-blocking requests have
218 // been submitted and cannot be canceled.
219 //
220 while (!IsNull (&Task->Subtasks, Link)) {
221 Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
222 Link = FatDestroySubtask (Subtask);
223 }
224
225 if (IsListEmpty (&Task->Subtasks)) {
226 RemoveEntryList (&Task->Link);
227 FreePool (Task);
228 } else {
229 //
230 // If one or more subtasks have been already submitted, set FileIoToken
231 // to NULL so that the callback won't signal the event.
232 //
233 Task->FileIoToken = NULL;
234 }
235
236 EfiReleaseLock (&FatTaskLock);
237 }
238
239 return Status;
240 }
241
242 EFI_STATUS
243 FatAccessVolumeDirty (
244 IN FAT_VOLUME *Volume,
245 IN IO_MODE IoMode,
246 IN VOID *DirtyValue
247 )
248 /*++
249
250 Routine Description:
251
252 Set the volume as dirty or not
253
254 Arguments:
255
256 Volume - FAT file system volume.
257 IoMode - The access mode.
258 DirtyValue - Set the volume as dirty or not.
259
260 Returns:
261
262 EFI_SUCCESS - Set the new FAT entry value sucessfully.
263 other - An error occurred when operation the FAT entries.
264
265 --*/
266 {
267 UINTN WriteCount;
268
269 WriteCount = Volume->FatEntrySize;
270 return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue, NULL);
271 }
272
273 /**
274 Invoke a notification event
275
276 @param Event Event whose notification function is being invoked.
277 @param Context The pointer to the notification function's context,
278 which is implementation-dependent.
279
280 **/
281 VOID
282 EFIAPI
283 FatOnAccessComplete (
284 IN EFI_EVENT Event,
285 IN VOID *Context
286 )
287 /*++
288
289 Routine Description:
290
291 Invoke a notification event
292 case #1. some subtasks are not completed when the FatOpenEx checks the Task->Subtasks
293 - sets Task->SubtaskCollected so callback to signal the event and free the task.
294 case #2. all subtasks are completed when the FatOpenEx checks the Task->Subtasks
295 - FatOpenEx signal the event and free the task.
296 Arguments:
297
298 Event - Event whose notification function is being invoked.
299 Context - The pointer to the notification function's context,
300 which is implementation-dependent.
301
302 --*/
303 {
304 EFI_STATUS Status;
305 FAT_SUBTASK *Subtask;
306 FAT_TASK *Task;
307
308 //
309 // Avoid someone in future breaks the below assumption.
310 //
311 ASSERT (EfiGetCurrentTpl () == FatTaskLock.Tpl);
312
313 Subtask = (FAT_SUBTASK *) Context;
314 Task = Subtask->Task;
315 Status = Subtask->DiskIo2Token.TransactionStatus;
316
317 ASSERT (Task->Signature == FAT_TASK_SIGNATURE);
318 ASSERT (Subtask->Signature == FAT_SUBTASK_SIGNATURE);
319
320 //
321 // Remove the task unconditionally
322 //
323 FatDestroySubtask (Subtask);
324
325 //
326 // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory).
327 //
328 if (Task->FileIoToken != NULL) {
329 if (IsListEmpty (&Task->Subtasks) || EFI_ERROR (Status)) {
330 Task->FileIoToken->Status = Status;
331 gBS->SignalEvent (Task->FileIoToken->Event);
332 //
333 // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored.
334 //
335 Task->FileIoToken = NULL;
336 }
337 }
338
339 if (IsListEmpty (&Task->Subtasks)) {
340 RemoveEntryList (&Task->Link);
341 FreePool (Task);
342 }
343 }
344
345 EFI_STATUS
346 FatDiskIo (
347 IN FAT_VOLUME *Volume,
348 IN IO_MODE IoMode,
349 IN UINT64 Offset,
350 IN UINTN BufferSize,
351 IN OUT VOID *Buffer,
352 IN FAT_TASK *Task
353 )
354 /*++
355
356 Routine Description:
357
358 General disk access function
359
360 Arguments:
361
362 Volume - FAT file system volume.
363 IoMode - The access mode (disk read/write or cache access).
364 Offset - The starting byte offset to read from.
365 BufferSize - Size of Buffer.
366 Buffer - Buffer containing read data.
367
368 Returns:
369
370 EFI_SUCCESS - The operation is performed successfully.
371 EFI_VOLUME_CORRUPTED - The accesss is
372 Others - The status of read/write the disk
373
374 --*/
375 {
376 EFI_STATUS Status;
377 EFI_DISK_IO_PROTOCOL *DiskIo;
378 EFI_DISK_READ IoFunction;
379 FAT_SUBTASK *Subtask;
380
381 //
382 // Verify the IO is in devices range
383 //
384 Status = EFI_VOLUME_CORRUPTED;
385 if (Offset + BufferSize <= Volume->VolumeSize) {
386 if (CACHE_ENABLED (IoMode)) {
387 //
388 // Access cache
389 //
390 Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer, Task);
391 } else {
392 //
393 // Access disk directly
394 //
395 if (Task == NULL) {
396 //
397 // Blocking access
398 //
399 DiskIo = Volume->DiskIo;
400 IoFunction = (IoMode == ReadDisk) ? DiskIo->ReadDisk : DiskIo->WriteDisk;
401 Status = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);
402 } else {
403 //
404 // Non-blocking access
405 //
406 Subtask = AllocateZeroPool (sizeof (*Subtask));
407 if (Subtask == NULL) {
408 Status = EFI_OUT_OF_RESOURCES;
409 } else {
410 Subtask->Signature = FAT_SUBTASK_SIGNATURE;
411 Subtask->Task = Task;
412 Subtask->Write = (BOOLEAN) (IoMode == WriteDisk);
413 Subtask->Offset = Offset;
414 Subtask->Buffer = Buffer;
415 Subtask->BufferSize = BufferSize;
416 Status = gBS->CreateEvent (
417 EVT_NOTIFY_SIGNAL,
418 TPL_NOTIFY,
419 FatOnAccessComplete,
420 Subtask,
421 &Subtask->DiskIo2Token.Event
422 );
423 if (!EFI_ERROR (Status)) {
424 InsertTailList (&Task->Subtasks, &Subtask->Link);
425 } else {
426 FreePool (Subtask);
427 }
428 }
429 }
430 }
431 }
432
433 if (EFI_ERROR (Status)) {
434 Volume->DiskError = TRUE;
435 DEBUG ((EFI_D_ERROR, "FatDiskIo: error %r\n", Status));
436 }
437
438 return Status;
439 }
440
441 VOID
442 FatAcquireLock (
443 VOID
444 )
445 /*++
446
447 Routine Description:
448
449 Lock the volume.
450
451 Arguments:
452
453 None.
454
455 Returns:
456
457 None.
458
459 --*/
460 {
461 EfiAcquireLock (&FatFsLock);
462 }
463
464 EFI_STATUS
465 FatAcquireLockOrFail (
466 VOID
467 )
468 /*++
469
470 Routine Description:
471
472 Lock the volume.
473 If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
474 Otherwise, EFI_SUCCESS is returned.
475
476 Arguments:
477
478 None.
479
480 Returns:
481
482 EFI_SUCCESS - The volume is locked.
483 EFI_ACCESS_DENIED - The volume could not be locked because it is already locked.
484
485 --*/
486 {
487 return EfiAcquireLockOrFail (&FatFsLock);
488 }
489
490 VOID
491 FatReleaseLock (
492 VOID
493 )
494 /*++
495
496 Routine Description:
497
498 Unlock the volume.
499
500 Arguments:
501
502 Null.
503
504 Returns:
505
506 None.
507
508 --*/
509 {
510 EfiReleaseLock (&FatFsLock);
511 }
512
513 VOID
514 FatFreeDirEnt (
515 IN FAT_DIRENT *DirEnt
516 )
517 /*++
518
519 Routine Description:
520
521 Free directory entry.
522
523 Arguments:
524
525 DirEnt - The directory entry to be freed.
526
527 Returns:
528
529 None.
530
531 --*/
532 {
533 if (DirEnt->FileString != NULL) {
534 FreePool (DirEnt->FileString);
535 }
536
537 FreePool (DirEnt);
538 }
539
540 VOID
541 FatFreeVolume (
542 IN FAT_VOLUME *Volume
543 )
544 /*++
545
546 Routine Description:
547
548 Free volume structure (including the contents of directory cache and disk cache).
549
550 Arguments:
551
552 Volume - The volume structure to be freed.
553
554 Returns:
555
556 None.
557
558 --*/
559 {
560 //
561 // Free disk cache
562 //
563 if (Volume->CacheBuffer != NULL) {
564 FreePool (Volume->CacheBuffer);
565 }
566 //
567 // Free directory cache
568 //
569 FatCleanupODirCache (Volume);
570 FreePool (Volume);
571 }
572
573 VOID
574 FatEfiTimeToFatTime (
575 IN EFI_TIME *ETime,
576 OUT FAT_DATE_TIME *FTime
577 )
578 /*++
579
580 Routine Description:
581
582 Translate EFI time to FAT time.
583
584 Arguments:
585
586 ETime - The time of EFI_TIME.
587 FTime - The time of FAT_DATE_TIME.
588
589 Returns:
590
591 None.
592
593 --*/
594 {
595 //
596 // ignores timezone info in source ETime
597 //
598 if (ETime->Year > 1980) {
599 FTime->Date.Year = (UINT16) (ETime->Year - 1980);
600 }
601
602 if (ETime->Year >= 1980 + FAT_MAX_YEAR_FROM_1980) {
603 FTime->Date.Year = FAT_MAX_YEAR_FROM_1980;
604 }
605
606 FTime->Date.Month = ETime->Month;
607 FTime->Date.Day = ETime->Day;
608 FTime->Time.Hour = ETime->Hour;
609 FTime->Time.Minute = ETime->Minute;
610 FTime->Time.DoubleSecond = (UINT16) (ETime->Second / 2);
611 }
612
613 VOID
614 FatFatTimeToEfiTime (
615 IN FAT_DATE_TIME *FTime,
616 OUT EFI_TIME *ETime
617 )
618 /*++
619
620 Routine Description:
621
622 Translate Fat time to EFI time.
623
624 Arguments:
625
626 FTime - The time of FAT_DATE_TIME.
627 ETime - The time of EFI_TIME.
628
629 Returns:
630
631 None.
632
633 --*/
634 {
635 ETime->Year = (UINT16) (FTime->Date.Year + 1980);
636 ETime->Month = (UINT8) FTime->Date.Month;
637 ETime->Day = (UINT8) FTime->Date.Day;
638 ETime->Hour = (UINT8) FTime->Time.Hour;
639 ETime->Minute = (UINT8) FTime->Time.Minute;
640 ETime->Second = (UINT8) (FTime->Time.DoubleSecond * 2);
641 ETime->Nanosecond = 0;
642 ETime->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
643 ETime->Daylight = 0;
644 }
645
646 VOID
647 FatGetCurrentFatTime (
648 OUT FAT_DATE_TIME *FatNow
649 )
650 /*++
651
652 Routine Description:
653
654 Get Current FAT time.
655
656 Arguments:
657
658 FatNow - Current FAT time.
659
660 Returns:
661
662 None.
663
664 --*/
665 {
666 EFI_STATUS Status;
667 EFI_TIME Now;
668
669 Status = gRT->GetTime (&Now, NULL);
670 if (!EFI_ERROR (Status)) {
671 FatEfiTimeToFatTime (&Now, FatNow);
672 } else {
673 ZeroMem (&Now, sizeof (EFI_TIME));
674 Now.Year = 1980;
675 Now.Month = 1;
676 Now.Day = 1;
677 FatEfiTimeToFatTime (&Now, FatNow);
678 }
679 }
680
681 BOOLEAN
682 FatIsValidTime (
683 IN EFI_TIME *Time
684 )
685 /*++
686
687 Routine Description:
688
689 Check whether a time is valid.
690
691 Arguments:
692
693 Time - The time of EFI_TIME.
694
695 Returns:
696
697 TRUE - The time is valid.
698 FALSE - The time is not valid.
699
700 --*/
701 {
702 UINTN Day;
703 BOOLEAN ValidTime;
704
705 ValidTime = TRUE;
706
707 //
708 // Check the fields for range problems
709 // Fat can only support from 1980
710 //
711 if (Time->Year < 1980 ||
712 Time->Month < 1 ||
713 Time->Month > 12 ||
714 Time->Day < 1 ||
715 Time->Day > 31 ||
716 Time->Hour > 23 ||
717 Time->Minute > 59 ||
718 Time->Second > 59 ||
719 Time->Nanosecond > 999999999
720 ) {
721
722 ValidTime = FALSE;
723
724 } else {
725 //
726 // Perform a more specific check of the day of the month
727 //
728 Day = mMonthDays[Time->Month - 1];
729 if (Time->Month == 2 && IS_LEAP_YEAR (Time->Year)) {
730 Day += 1;
731 //
732 // 1 extra day this month
733 //
734 }
735 if (Time->Day > Day) {
736 ValidTime = FALSE;
737 }
738 }
739
740 return ValidTime;
741 }