]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/Misc.c
FatPkg: Refine casting expression result to bigger size
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / Misc.c
CommitLineData
cae7420b
DB
1/** @file\r
2 Miscellaneous functions.\r
b9ec9330 3\r
149d6335 4Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
6163cc98 5This program and the accompanying materials are licensed and made available\r
b9ec9330
QH
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
cae7420b 14**/\r
b9ec9330 15\r
cae7420b
DB
16#include "Fat.h"\r
17UINT8 mMonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
b9ec9330 18\r
cae7420b 19/**\r
b9ec9330 20\r
cae7420b 21 Create the task\r
b9ec9330 22\r
cae7420b
DB
23 @param IFile - The instance of the open file.\r
24 @param Token - A pointer to the token associated with the transaction.\r
b9ec9330 25\r
cae7420b 26 @return FAT_TASK * - Return the task instance.\r
b9ec9330 27\r
cae7420b 28**/\r
149d6335
RN
29FAT_TASK *\r
30FatCreateTask (\r
31 FAT_IFILE *IFile,\r
32 EFI_FILE_IO_TOKEN *Token\r
33 )\r
149d6335
RN
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
cae7420b 48/**\r
149d6335 49\r
cae7420b 50 Destroy the task.\r
149d6335 51\r
cae7420b 52 @param Task - The task to be destroyed.\r
149d6335 53\r
149d6335 54**/\r
cae7420b
DB
55VOID\r
56FatDestroyTask (\r
57 FAT_TASK *Task\r
58 )\r
149d6335
RN
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
149d6335
RN
68 FreePool (Task);\r
69}\r
70\r
cae7420b 71/**\r
149d6335
RN
72\r
73 Wait all non-blocking requests complete.\r
74\r
cae7420b 75 @param IFile - The instance of the open file.\r
149d6335 76\r
149d6335 77**/\r
cae7420b
DB
78VOID\r
79FatWaitNonblockingTask (\r
80 FAT_IFILE *IFile\r
81 )\r
149d6335
RN
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
cae7420b 92/**\r
149d6335
RN
93\r
94 Remove the subtask from subtask list.\r
95\r
cae7420b 96 @param Subtask - The subtask to be removed.\r
149d6335 97\r
cae7420b 98 @return LIST_ENTRY * - The next node in the list.\r
149d6335 99\r
cae7420b
DB
100**/\r
101LIST_ENTRY *\r
102FatDestroySubtask (\r
103 FAT_SUBTASK *Subtask\r
104 )\r
149d6335
RN
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
cae7420b
DB
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
149d6335
RN
127EFI_STATUS\r
128FatQueueTask (\r
129 IN FAT_IFILE *IFile,\r
130 IN FAT_TASK *Task\r
131 )\r
149d6335
RN
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
cae7420b
DB
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
b9ec9330
QH
223EFI_STATUS\r
224FatAccessVolumeDirty (\r
225 IN FAT_VOLUME *Volume,\r
226 IN IO_MODE IoMode,\r
227 IN VOID *DirtyValue\r
228 )\r
b9ec9330
QH
229{\r
230 UINTN WriteCount;\r
231\r
232 WriteCount = Volume->FatEntrySize;\r
149d6335
RN
233 return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue, NULL);\r
234}\r
235\r
236/**\r
cae7420b 237 Invoke a notification event.\r
149d6335
RN
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
149d6335
RN
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
b9ec9330
QH
290}\r
291\r
cae7420b
DB
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
b9ec9330
QH
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
149d6335
RN
314 IN OUT VOID *Buffer,\r
315 IN FAT_TASK *Task\r
b9ec9330 316 )\r
b9ec9330
QH
317{\r
318 EFI_STATUS Status;\r
319 EFI_DISK_IO_PROTOCOL *DiskIo;\r
320 EFI_DISK_READ IoFunction;\r
149d6335 321 FAT_SUBTASK *Subtask;\r
b9ec9330
QH
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
149d6335 332 Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer, Task);\r
b9ec9330
QH
333 } else {\r
334 //\r
335 // Access disk directly\r
336 //\r
149d6335
RN
337 if (Task == NULL) {\r
338 //\r
339 // Blocking access\r
340 //\r
341 DiskIo = Volume->DiskIo;\r
c1680e88 342 IoFunction = (IoMode == ReadDisk) ? DiskIo->ReadDisk : DiskIo->WriteDisk;\r
149d6335
RN
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
c1680e88 354 Subtask->Write = (BOOLEAN) (IoMode == WriteDisk);\r
149d6335
RN
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
b9ec9330
QH
372 }\r
373 }\r
374\r
375 if (EFI_ERROR (Status)) {\r
376 Volume->DiskError = TRUE;\r
149d6335 377 DEBUG ((EFI_D_ERROR, "FatDiskIo: error %r\n", Status));\r
b9ec9330
QH
378 }\r
379\r
380 return Status;\r
381}\r
382\r
cae7420b
DB
383/**\r
384\r
385 Lock the volume.\r
386\r
387**/\r
b9ec9330
QH
388VOID\r
389FatAcquireLock (\r
390 VOID\r
391 )\r
b9ec9330
QH
392{\r
393 EfiAcquireLock (&FatFsLock);\r
394}\r
395\r
cae7420b 396/**\r
b9ec9330 397\r
25ce9b1f
QH
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
b9ec9330 401\r
cae7420b
DB
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
b9ec9330 404\r
cae7420b
DB
405**/\r
406EFI_STATUS\r
407FatAcquireLockOrFail (\r
408 VOID\r
409 )\r
b9ec9330 410{\r
25ce9b1f 411 return EfiAcquireLockOrFail (&FatFsLock);\r
b9ec9330
QH
412}\r
413\r
cae7420b
DB
414/**\r
415\r
416 Unlock the volume.\r
417\r
418**/\r
b9ec9330
QH
419VOID\r
420FatReleaseLock (\r
421 VOID\r
422 )\r
b9ec9330
QH
423{\r
424 EfiReleaseLock (&FatFsLock);\r
425}\r
426\r
cae7420b 427/**\r
b9ec9330
QH
428\r
429 Free directory entry.\r
430\r
cae7420b 431 @param DirEnt - The directory entry to be freed.\r
b9ec9330 432\r
cae7420b
DB
433**/\r
434VOID\r
435FatFreeDirEnt (\r
436 IN FAT_DIRENT *DirEnt\r
437 )\r
b9ec9330
QH
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
cae7420b 446/**\r
b9ec9330
QH
447\r
448 Free volume structure (including the contents of directory cache and disk cache).\r
449\r
cae7420b 450 @param Volume - The volume structure to be freed.\r
b9ec9330 451\r
cae7420b
DB
452**/\r
453VOID\r
454FatFreeVolume (\r
455 IN FAT_VOLUME *Volume\r
456 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
479VOID\r
480FatEfiTimeToFatTime (\r
481 IN EFI_TIME *ETime,\r
482 OUT FAT_DATE_TIME *FTime\r
483 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
511VOID\r
512FatFatTimeToEfiTime (\r
513 IN FAT_DATE_TIME *FTime,\r
514 OUT EFI_TIME *ETime\r
515 )\r
b9ec9330
QH
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
cae7420b 528/**\r
b9ec9330
QH
529\r
530 Get Current FAT time.\r
531\r
cae7420b 532 @param FatNow - Current FAT time.\r
b9ec9330 533\r
cae7420b
DB
534**/\r
535VOID\r
536FatGetCurrentFatTime (\r
537 OUT FAT_DATE_TIME *FatNow\r
538 )\r
b9ec9330 539{\r
ab99061c
OM
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
b9ec9330
QH
553}\r
554\r
cae7420b 555/**\r
b9ec9330
QH
556\r
557 Check whether a time is valid.\r
558\r
cae7420b 559 @param Time - The time of EFI_TIME.\r
b9ec9330 560\r
cae7420b
DB
561 @retval TRUE - The time is valid.\r
562 @retval FALSE - The time is not valid.\r
b9ec9330 563\r
cae7420b
DB
564**/\r
565BOOLEAN\r
566FatIsValidTime (\r
567 IN EFI_TIME *Time\r
568 )\r
b9ec9330 569{\r
b9ec9330
QH
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
3c8b45c8 596 Day = mMonthDays[Time->Month - 1];\r
b9ec9330
QH
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