]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - FatPkg/EnhancedFatDxe/Misc.c
BaseTools: use set instead of list for a variable to be used with in
[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 FAT_SUBTASK *Subtask;\r
136\r
137 //\r
138 // Sometimes the Task doesn't contain any subtasks, signal the event directly.\r
139 //\r
140 if (IsListEmpty (&Task->Subtasks)) {\r
141 Task->FileIoToken->Status = EFI_SUCCESS;\r
142 gBS->SignalEvent (Task->FileIoToken->Event);\r
143 FreePool (Task);\r
144 return EFI_SUCCESS;\r
145 }\r
146\r
147 EfiAcquireLock (&FatTaskLock);\r
148 InsertTailList (&IFile->Tasks, &Task->Link);\r
149 EfiReleaseLock (&FatTaskLock);\r
150\r
151 Status = EFI_SUCCESS;\r
152 for ( Link = GetFirstNode (&Task->Subtasks)\r
153 ; !IsNull (&Task->Subtasks, Link)\r
154 ; Link = GetNextNode (&Task->Subtasks, Link)\r
155 ) {\r
156 Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
157 if (Subtask->Write) {\r
158 \r
159 Status = IFile->OFile->Volume->DiskIo2->WriteDiskEx (\r
160 IFile->OFile->Volume->DiskIo2,\r
161 IFile->OFile->Volume->MediaId,\r
162 Subtask->Offset,\r
163 &Subtask->DiskIo2Token,\r
164 Subtask->BufferSize,\r
165 Subtask->Buffer\r
166 );\r
167 } else {\r
168 Status = IFile->OFile->Volume->DiskIo2->ReadDiskEx (\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 }\r
177 if (EFI_ERROR (Status)) {\r
178 break;\r
179 }\r
180 }\r
181\r
182 if (EFI_ERROR (Status)) {\r
183 EfiAcquireLock (&FatTaskLock);\r
184 //\r
185 // Remove all the remaining subtasks when failure.\r
186 // We shouldn't remove all the tasks because the non-blocking requests have\r
187 // been submitted and cannot be canceled.\r
188 //\r
189 while (!IsNull (&Task->Subtasks, Link)) {\r
190 Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
191 Link = FatDestroySubtask (Subtask);\r
192 }\r
193\r
194 if (IsListEmpty (&Task->Subtasks)) {\r
195 RemoveEntryList (&Task->Link);\r
196 FreePool (Task);\r
197 } else {\r
198 //\r
199 // If one or more subtasks have been already submitted, set FileIoToken\r
200 // to NULL so that the callback won't signal the event.\r
201 //\r
202 Task->FileIoToken = NULL;\r
203 }\r
204\r
205 EfiReleaseLock (&FatTaskLock);\r
206 }\r
207\r
208 return Status;\r
209}\r
210\r
211/**\r
212\r
213 Set the volume as dirty or not.\r
214\r
215 @param Volume - FAT file system volume.\r
216 @param IoMode - The access mode.\r
217 @param DirtyValue - Set the volume as dirty or not.\r
218\r
219 @retval EFI_SUCCESS - Set the new FAT entry value sucessfully.\r
220 @return other - An error occurred when operation the FAT entries.\r
221\r
222**/\r
223EFI_STATUS\r
224FatAccessVolumeDirty (\r
225 IN FAT_VOLUME *Volume,\r
226 IN IO_MODE IoMode,\r
227 IN VOID *DirtyValue\r
228 )\r
229{\r
230 UINTN WriteCount;\r
231\r
232 WriteCount = Volume->FatEntrySize;\r
233 return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue, NULL);\r
234}\r
235\r
236/**\r
237 Invoke a notification event.\r
238\r
239 @param Event Event whose notification function is being invoked.\r
240 @param Context The pointer to the notification function's context,\r
241 which is implementation-dependent.\r
242\r
243**/\r
244VOID\r
245EFIAPI\r
246FatOnAccessComplete (\r
247 IN EFI_EVENT Event,\r
248 IN VOID *Context\r
249 )\r
250{\r
251 EFI_STATUS Status;\r
252 FAT_SUBTASK *Subtask;\r
253 FAT_TASK *Task;\r
254\r
255 //\r
256 // Avoid someone in future breaks the below assumption.\r
257 //\r
258 ASSERT (EfiGetCurrentTpl () == FatTaskLock.Tpl);\r
259\r
260 Subtask = (FAT_SUBTASK *) Context;\r
261 Task = Subtask->Task;\r
262 Status = Subtask->DiskIo2Token.TransactionStatus;\r
263\r
264 ASSERT (Task->Signature == FAT_TASK_SIGNATURE);\r
265 ASSERT (Subtask->Signature == FAT_SUBTASK_SIGNATURE);\r
266\r
267 //\r
268 // Remove the task unconditionally\r
269 //\r
270 FatDestroySubtask (Subtask);\r
271\r
272 //\r
273 // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory).\r
274 //\r
275 if (Task->FileIoToken != NULL) {\r
276 if (IsListEmpty (&Task->Subtasks) || EFI_ERROR (Status)) {\r
277 Task->FileIoToken->Status = Status;\r
278 gBS->SignalEvent (Task->FileIoToken->Event);\r
279 //\r
280 // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored.\r
281 //\r
282 Task->FileIoToken = NULL;\r
283 }\r
284 }\r
285\r
286 if (IsListEmpty (&Task->Subtasks)) {\r
287 RemoveEntryList (&Task->Link);\r
288 FreePool (Task);\r
289 }\r
290}\r
291\r
292/**\r
293\r
294 General disk access function.\r
295\r
296 @param Volume - FAT file system volume.\r
297 @param IoMode - The access mode (disk read/write or cache access).\r
298 @param Offset - The starting byte offset to read from.\r
299 @param BufferSize - Size of Buffer.\r
300 @param Buffer - Buffer containing read data.\r
301 @param Task point to task instance.\r
302\r
303 @retval EFI_SUCCESS - The operation is performed successfully.\r
304 @retval EFI_VOLUME_CORRUPTED - The accesss is\r
305 @return Others - The status of read/write the disk\r
306\r
307**/\r
308EFI_STATUS\r
309FatDiskIo (\r
310 IN FAT_VOLUME *Volume,\r
311 IN IO_MODE IoMode,\r
312 IN UINT64 Offset,\r
313 IN UINTN BufferSize,\r
314 IN OUT VOID *Buffer,\r
315 IN FAT_TASK *Task\r
316 )\r
317{\r
318 EFI_STATUS Status;\r
319 EFI_DISK_IO_PROTOCOL *DiskIo;\r
320 EFI_DISK_READ IoFunction;\r
321 FAT_SUBTASK *Subtask;\r
322\r
323 //\r
324 // Verify the IO is in devices range\r
325 //\r
326 Status = EFI_VOLUME_CORRUPTED;\r
327 if (Offset + BufferSize <= Volume->VolumeSize) {\r
328 if (CACHE_ENABLED (IoMode)) {\r
329 //\r
330 // Access cache\r
331 //\r
332 Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer, Task);\r
333 } else {\r
334 //\r
335 // Access disk directly\r
336 //\r
337 if (Task == NULL) {\r
338 //\r
339 // Blocking access\r
340 //\r
341 DiskIo = Volume->DiskIo;\r
342 IoFunction = (IoMode == ReadDisk) ? DiskIo->ReadDisk : DiskIo->WriteDisk;\r
343 Status = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);\r
344 } else {\r
345 //\r
346 // Non-blocking access\r
347 //\r
348 Subtask = AllocateZeroPool (sizeof (*Subtask));\r
349 if (Subtask == NULL) {\r
350 Status = EFI_OUT_OF_RESOURCES;\r
351 } else {\r
352 Subtask->Signature = FAT_SUBTASK_SIGNATURE;\r
353 Subtask->Task = Task;\r
354 Subtask->Write = (BOOLEAN) (IoMode == WriteDisk);\r
355 Subtask->Offset = Offset;\r
356 Subtask->Buffer = Buffer;\r
357 Subtask->BufferSize = BufferSize;\r
358 Status = gBS->CreateEvent (\r
359 EVT_NOTIFY_SIGNAL,\r
360 TPL_NOTIFY,\r
361 FatOnAccessComplete,\r
362 Subtask,\r
363 &Subtask->DiskIo2Token.Event\r
364 );\r
365 if (!EFI_ERROR (Status)) {\r
366 InsertTailList (&Task->Subtasks, &Subtask->Link);\r
367 } else {\r
368 FreePool (Subtask);\r
369 }\r
370 }\r
371 }\r
372 }\r
373 }\r
374\r
375 if (EFI_ERROR (Status)) {\r
376 Volume->DiskError = TRUE;\r
377 DEBUG ((EFI_D_ERROR, "FatDiskIo: error %r\n", Status));\r
378 }\r
379\r
380 return Status;\r
381}\r
382\r
383/**\r
384\r
385 Lock the volume.\r
386\r
387**/\r
388VOID\r
389FatAcquireLock (\r
390 VOID\r
391 )\r
392{\r
393 EfiAcquireLock (&FatFsLock);\r
394}\r
395\r
396/**\r
397\r
398 Lock the volume.\r
399 If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.\r
400 Otherwise, EFI_SUCCESS is returned.\r
401\r
402 @retval EFI_SUCCESS - The volume is locked.\r
403 @retval EFI_ACCESS_DENIED - The volume could not be locked because it is already locked.\r
404\r
405**/\r
406EFI_STATUS\r
407FatAcquireLockOrFail (\r
408 VOID\r
409 )\r
410{\r
411 return EfiAcquireLockOrFail (&FatFsLock);\r
412}\r
413\r
414/**\r
415\r
416 Unlock the volume.\r
417\r
418**/\r
419VOID\r
420FatReleaseLock (\r
421 VOID\r
422 )\r
423{\r
424 EfiReleaseLock (&FatFsLock);\r
425}\r
426\r
427/**\r
428\r
429 Free directory entry.\r
430\r
431 @param DirEnt - The directory entry to be freed.\r
432\r
433**/\r
434VOID\r
435FatFreeDirEnt (\r
436 IN FAT_DIRENT *DirEnt\r
437 )\r
438{\r
439 if (DirEnt->FileString != NULL) {\r
440 FreePool (DirEnt->FileString);\r
441 }\r
442\r
443 FreePool (DirEnt);\r
444}\r
445\r
446/**\r
447\r
448 Free volume structure (including the contents of directory cache and disk cache).\r
449\r
450 @param Volume - The volume structure to be freed.\r
451\r
452**/\r
453VOID\r
454FatFreeVolume (\r
455 IN FAT_VOLUME *Volume\r
456 )\r
457{\r
458 //\r
459 // Free disk cache\r
460 //\r
461 if (Volume->CacheBuffer != NULL) {\r
462 FreePool (Volume->CacheBuffer);\r
463 }\r
464 //\r
465 // Free directory cache\r
466 //\r
467 FatCleanupODirCache (Volume);\r
468 FreePool (Volume);\r
469}\r
470\r
471/**\r
472\r
473 Translate EFI time to FAT time.\r
474\r
475 @param ETime - The time of EFI_TIME.\r
476 @param FTime - The time of FAT_DATE_TIME.\r
477\r
478**/\r
479VOID\r
480FatEfiTimeToFatTime (\r
481 IN EFI_TIME *ETime,\r
482 OUT FAT_DATE_TIME *FTime\r
483 )\r
484{\r
485 //\r
486 // ignores timezone info in source ETime\r
487 //\r
488 if (ETime->Year > 1980) {\r
489 FTime->Date.Year = (UINT16) (ETime->Year - 1980);\r
490 }\r
491\r
492 if (ETime->Year >= 1980 + FAT_MAX_YEAR_FROM_1980) {\r
493 FTime->Date.Year = FAT_MAX_YEAR_FROM_1980;\r
494 }\r
495\r
496 FTime->Date.Month = ETime->Month;\r
497 FTime->Date.Day = ETime->Day;\r
498 FTime->Time.Hour = ETime->Hour;\r
499 FTime->Time.Minute = ETime->Minute;\r
500 FTime->Time.DoubleSecond = (UINT16) (ETime->Second / 2);\r
501}\r
502\r
503/**\r
504\r
505 Translate Fat time to EFI time.\r
506\r
507 @param FTime - The time of FAT_DATE_TIME.\r
508 @param ETime - The time of EFI_TIME..\r
509\r
510**/\r
511VOID\r
512FatFatTimeToEfiTime (\r
513 IN FAT_DATE_TIME *FTime,\r
514 OUT EFI_TIME *ETime\r
515 )\r
516{\r
517 ETime->Year = (UINT16) (FTime->Date.Year + 1980);\r
518 ETime->Month = (UINT8) FTime->Date.Month;\r
519 ETime->Day = (UINT8) FTime->Date.Day;\r
520 ETime->Hour = (UINT8) FTime->Time.Hour;\r
521 ETime->Minute = (UINT8) FTime->Time.Minute;\r
522 ETime->Second = (UINT8) (FTime->Time.DoubleSecond * 2);\r
523 ETime->Nanosecond = 0;\r
524 ETime->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
525 ETime->Daylight = 0;\r
526}\r
527\r
528/**\r
529\r
530 Get Current FAT time.\r
531\r
532 @param FatNow - Current FAT time.\r
533\r
534**/\r
535VOID\r
536FatGetCurrentFatTime (\r
537 OUT FAT_DATE_TIME *FatNow\r
538 )\r
539{\r
540 EFI_STATUS Status;\r
541 EFI_TIME Now;\r
542\r
543 Status = gRT->GetTime (&Now, NULL);\r
544 if (!EFI_ERROR (Status)) {\r
545 FatEfiTimeToFatTime (&Now, FatNow);\r
546 } else {\r
547 ZeroMem (&Now, sizeof (EFI_TIME));\r
548 Now.Year = 1980;\r
549 Now.Month = 1;\r
550 Now.Day = 1;\r
551 FatEfiTimeToFatTime (&Now, FatNow);\r
552 }\r
553}\r
554\r
555/**\r
556\r
557 Check whether a time is valid.\r
558\r
559 @param Time - The time of EFI_TIME.\r
560\r
561 @retval TRUE - The time is valid.\r
562 @retval FALSE - The time is not valid.\r
563\r
564**/\r
565BOOLEAN\r
566FatIsValidTime (\r
567 IN EFI_TIME *Time\r
568 )\r
569{\r
570 UINTN Day;\r
571 BOOLEAN ValidTime;\r
572\r
573 ValidTime = TRUE;\r
574\r
575 //\r
576 // Check the fields for range problems\r
577 // Fat can only support from 1980\r
578 //\r
579 if (Time->Year < 1980 ||\r
580 Time->Month < 1 ||\r
581 Time->Month > 12 ||\r
582 Time->Day < 1 ||\r
583 Time->Day > 31 ||\r
584 Time->Hour > 23 ||\r
585 Time->Minute > 59 ||\r
586 Time->Second > 59 ||\r
587 Time->Nanosecond > 999999999\r
588 ) {\r
589\r
590 ValidTime = FALSE;\r
591\r
592 } else {\r
593 //\r
594 // Perform a more specific check of the day of the month\r
595 //\r
596 Day = mMonthDays[Time->Month - 1];\r
597 if (Time->Month == 2 && IS_LEAP_YEAR (Time->Year)) {\r
598 Day += 1;\r
599 //\r
600 // 1 extra day this month\r
601 //\r
602 }\r
603 if (Time->Day > Day) {\r
604 ValidTime = FALSE;\r
605 }\r
606 }\r
607\r
608 return ValidTime;\r
609}\r