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