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