]>
git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/EnhancedFatDxe/Misc.c
2 Miscellaneous functions.
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 UINT8 mMonthDays
[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
17 @param IFile - The instance of the open file.
18 @param Token - A pointer to the token associated with the transaction.
20 @return FAT_TASK * - Return the task instance.
26 EFI_FILE_IO_TOKEN
*Token
31 Task
= AllocateZeroPool (sizeof (*Task
));
33 Task
->Signature
= FAT_TASK_SIGNATURE
;
35 Task
->FileIoToken
= Token
;
36 InitializeListHead (&Task
->Subtasks
);
37 InitializeListHead (&Task
->Link
);
46 @param Task - The task to be destroyed.
57 Link
= GetFirstNode (&Task
->Subtasks
);
58 while (!IsNull (&Task
->Subtasks
, Link
)) {
59 Subtask
= CR (Link
, FAT_SUBTASK
, Link
, FAT_SUBTASK_SIGNATURE
);
60 Link
= FatDestroySubtask (Subtask
);
67 Wait all non-blocking requests complete.
69 @param IFile - The instance of the open file.
73 FatWaitNonblockingTask (
77 BOOLEAN TaskQueueEmpty
;
80 EfiAcquireLock (&FatTaskLock
);
81 TaskQueueEmpty
= IsListEmpty (&IFile
->Tasks
);
82 EfiReleaseLock (&FatTaskLock
);
83 } while (!TaskQueueEmpty
);
88 Remove the subtask from subtask list.
90 @param Subtask - The subtask to be removed.
92 @return LIST_ENTRY * - The next node in the list.
102 gBS
->CloseEvent (Subtask
->DiskIo2Token
.Event
);
104 Link
= RemoveEntryList (&Subtask
->Link
);
114 @param IFile - The instance of the open file.
115 @param Task - The task to be executed.
117 @retval EFI_SUCCESS - The task was executed sucessfully.
118 @return other - An error occurred when executing the task.
129 LIST_ENTRY
*NextLink
;
130 FAT_SUBTASK
*Subtask
;
133 // Sometimes the Task doesn't contain any subtasks, signal the event directly.
135 if (IsListEmpty (&Task
->Subtasks
)) {
136 Task
->FileIoToken
->Status
= EFI_SUCCESS
;
137 gBS
->SignalEvent (Task
->FileIoToken
->Event
);
142 EfiAcquireLock (&FatTaskLock
);
143 InsertTailList (&IFile
->Tasks
, &Task
->Link
);
144 EfiReleaseLock (&FatTaskLock
);
146 Status
= EFI_SUCCESS
;
148 // Use NextLink to store the next link of the list, because Link might be remove from the
149 // doubly-linked list and get freed in the end of current loop.
151 // Also, list operation APIs like IsNull() and GetNextNode() are avoided during the loop, since
152 // they may check the validity of doubly-linked lists by traversing them. These APIs cannot
153 // handle list elements being removed during the traverse.
155 for ( Link
= GetFirstNode (&Task
->Subtasks
), NextLink
= GetNextNode (&Task
->Subtasks
, Link
)
156 ; Link
!= &Task
->Subtasks
157 ; Link
= NextLink
, NextLink
= Link
->ForwardLink
159 Subtask
= CR (Link
, FAT_SUBTASK
, Link
, FAT_SUBTASK_SIGNATURE
);
160 if (Subtask
->Write
) {
162 Status
= IFile
->OFile
->Volume
->DiskIo2
->WriteDiskEx (
163 IFile
->OFile
->Volume
->DiskIo2
,
164 IFile
->OFile
->Volume
->MediaId
,
166 &Subtask
->DiskIo2Token
,
171 Status
= IFile
->OFile
->Volume
->DiskIo2
->ReadDiskEx (
172 IFile
->OFile
->Volume
->DiskIo2
,
173 IFile
->OFile
->Volume
->MediaId
,
175 &Subtask
->DiskIo2Token
,
180 if (EFI_ERROR (Status
)) {
185 if (EFI_ERROR (Status
)) {
186 EfiAcquireLock (&FatTaskLock
);
188 // Remove all the remaining subtasks when failure.
189 // We shouldn't remove all the tasks because the non-blocking requests have
190 // been submitted and cannot be canceled.
192 while (!IsNull (&Task
->Subtasks
, Link
)) {
193 Subtask
= CR (Link
, FAT_SUBTASK
, Link
, FAT_SUBTASK_SIGNATURE
);
194 Link
= FatDestroySubtask (Subtask
);
197 if (IsListEmpty (&Task
->Subtasks
)) {
198 RemoveEntryList (&Task
->Link
);
202 // If one or more subtasks have been already submitted, set FileIoToken
203 // to NULL so that the callback won't signal the event.
205 Task
->FileIoToken
= NULL
;
208 EfiReleaseLock (&FatTaskLock
);
216 Set the volume as dirty or not.
218 @param Volume - FAT file system volume.
219 @param IoMode - The access mode.
220 @param DirtyValue - Set the volume as dirty or not.
222 @retval EFI_SUCCESS - Set the new FAT entry value sucessfully.
223 @return other - An error occurred when operation the FAT entries.
227 FatAccessVolumeDirty (
228 IN FAT_VOLUME
*Volume
,
235 WriteCount
= Volume
->FatEntrySize
;
236 return FatDiskIo (Volume
, IoMode
, Volume
->FatPos
+ WriteCount
, WriteCount
, DirtyValue
, NULL
);
240 Invoke a notification event.
242 @param Event Event whose notification function is being invoked.
243 @param Context The pointer to the notification function's context,
244 which is implementation-dependent.
249 FatOnAccessComplete (
255 FAT_SUBTASK
*Subtask
;
259 // Avoid someone in future breaks the below assumption.
261 ASSERT (EfiGetCurrentTpl () == FatTaskLock
.Tpl
);
263 Subtask
= (FAT_SUBTASK
*) Context
;
264 Task
= Subtask
->Task
;
265 Status
= Subtask
->DiskIo2Token
.TransactionStatus
;
267 ASSERT (Task
->Signature
== FAT_TASK_SIGNATURE
);
268 ASSERT (Subtask
->Signature
== FAT_SUBTASK_SIGNATURE
);
271 // Remove the task unconditionally
273 FatDestroySubtask (Subtask
);
276 // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory).
278 if (Task
->FileIoToken
!= NULL
) {
279 if (IsListEmpty (&Task
->Subtasks
) || EFI_ERROR (Status
)) {
280 Task
->FileIoToken
->Status
= Status
;
281 gBS
->SignalEvent (Task
->FileIoToken
->Event
);
283 // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored.
285 Task
->FileIoToken
= NULL
;
289 if (IsListEmpty (&Task
->Subtasks
)) {
290 RemoveEntryList (&Task
->Link
);
297 General disk access function.
299 @param Volume - FAT file system volume.
300 @param IoMode - The access mode (disk read/write or cache access).
301 @param Offset - The starting byte offset to read from.
302 @param BufferSize - Size of Buffer.
303 @param Buffer - Buffer containing read data.
304 @param Task point to task instance.
306 @retval EFI_SUCCESS - The operation is performed successfully.
307 @retval EFI_VOLUME_CORRUPTED - The accesss is
308 @return Others - The status of read/write the disk
313 IN FAT_VOLUME
*Volume
,
322 EFI_DISK_IO_PROTOCOL
*DiskIo
;
323 EFI_DISK_READ IoFunction
;
324 FAT_SUBTASK
*Subtask
;
327 // Verify the IO is in devices range
329 Status
= EFI_VOLUME_CORRUPTED
;
330 if (Offset
+ BufferSize
<= Volume
->VolumeSize
) {
331 if (CACHE_ENABLED (IoMode
)) {
335 Status
= FatAccessCache (Volume
, CACHE_TYPE (IoMode
), RAW_ACCESS (IoMode
), Offset
, BufferSize
, Buffer
, Task
);
338 // Access disk directly
344 DiskIo
= Volume
->DiskIo
;
345 IoFunction
= (IoMode
== ReadDisk
) ? DiskIo
->ReadDisk
: DiskIo
->WriteDisk
;
346 Status
= IoFunction (DiskIo
, Volume
->MediaId
, Offset
, BufferSize
, Buffer
);
349 // Non-blocking access
351 Subtask
= AllocateZeroPool (sizeof (*Subtask
));
352 if (Subtask
== NULL
) {
353 Status
= EFI_OUT_OF_RESOURCES
;
355 Subtask
->Signature
= FAT_SUBTASK_SIGNATURE
;
356 Subtask
->Task
= Task
;
357 Subtask
->Write
= (BOOLEAN
) (IoMode
== WriteDisk
);
358 Subtask
->Offset
= Offset
;
359 Subtask
->Buffer
= Buffer
;
360 Subtask
->BufferSize
= BufferSize
;
361 Status
= gBS
->CreateEvent (
366 &Subtask
->DiskIo2Token
.Event
368 if (!EFI_ERROR (Status
)) {
369 InsertTailList (&Task
->Subtasks
, &Subtask
->Link
);
378 if (EFI_ERROR (Status
)) {
379 Volume
->DiskError
= TRUE
;
380 DEBUG ((EFI_D_ERROR
, "FatDiskIo: error %r\n", Status
));
396 EfiAcquireLock (&FatFsLock
);
402 If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
403 Otherwise, EFI_SUCCESS is returned.
405 @retval EFI_SUCCESS - The volume is locked.
406 @retval EFI_ACCESS_DENIED - The volume could not be locked because it is already locked.
410 FatAcquireLockOrFail (
414 return EfiAcquireLockOrFail (&FatFsLock
);
427 EfiReleaseLock (&FatFsLock
);
432 Free directory entry.
434 @param DirEnt - The directory entry to be freed.
439 IN FAT_DIRENT
*DirEnt
442 if (DirEnt
->FileString
!= NULL
) {
443 FreePool (DirEnt
->FileString
);
451 Free volume structure (including the contents of directory cache and disk cache).
453 @param Volume - The volume structure to be freed.
458 IN FAT_VOLUME
*Volume
464 if (Volume
->CacheBuffer
!= NULL
) {
465 FreePool (Volume
->CacheBuffer
);
468 // Free directory cache
470 FatCleanupODirCache (Volume
);
476 Translate EFI time to FAT time.
478 @param ETime - The time of EFI_TIME.
479 @param FTime - The time of FAT_DATE_TIME.
483 FatEfiTimeToFatTime (
485 OUT FAT_DATE_TIME
*FTime
489 // ignores timezone info in source ETime
491 if (ETime
->Year
> 1980) {
492 FTime
->Date
.Year
= (UINT16
) (ETime
->Year
- 1980);
495 if (ETime
->Year
>= 1980 + FAT_MAX_YEAR_FROM_1980
) {
496 FTime
->Date
.Year
= FAT_MAX_YEAR_FROM_1980
;
499 FTime
->Date
.Month
= ETime
->Month
;
500 FTime
->Date
.Day
= ETime
->Day
;
501 FTime
->Time
.Hour
= ETime
->Hour
;
502 FTime
->Time
.Minute
= ETime
->Minute
;
503 FTime
->Time
.DoubleSecond
= (UINT16
) (ETime
->Second
/ 2);
508 Translate Fat time to EFI time.
510 @param FTime - The time of FAT_DATE_TIME.
511 @param ETime - The time of EFI_TIME..
515 FatFatTimeToEfiTime (
516 IN FAT_DATE_TIME
*FTime
,
520 ETime
->Year
= (UINT16
) (FTime
->Date
.Year
+ 1980);
521 ETime
->Month
= (UINT8
) FTime
->Date
.Month
;
522 ETime
->Day
= (UINT8
) FTime
->Date
.Day
;
523 ETime
->Hour
= (UINT8
) FTime
->Time
.Hour
;
524 ETime
->Minute
= (UINT8
) FTime
->Time
.Minute
;
525 ETime
->Second
= (UINT8
) (FTime
->Time
.DoubleSecond
* 2);
526 ETime
->Nanosecond
= 0;
527 ETime
->TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
533 Get Current FAT time.
535 @param FatNow - Current FAT time.
539 FatGetCurrentFatTime (
540 OUT FAT_DATE_TIME
*FatNow
546 Status
= gRT
->GetTime (&Now
, NULL
);
547 if (!EFI_ERROR (Status
)) {
548 FatEfiTimeToFatTime (&Now
, FatNow
);
550 ZeroMem (&Now
, sizeof (EFI_TIME
));
554 FatEfiTimeToFatTime (&Now
, FatNow
);
560 Check whether a time is valid.
562 @param Time - The time of EFI_TIME.
564 @retval TRUE - The time is valid.
565 @retval FALSE - The time is not valid.
579 // Check the fields for range problems
580 // Fat can only support from 1980
582 if (Time
->Year
< 1980 ||
590 Time
->Nanosecond
> 999999999
597 // Perform a more specific check of the day of the month
599 Day
= mMonthDays
[Time
->Month
- 1];
600 if (Time
->Month
== 2 && IS_LEAP_YEAR (Time
->Year
)) {
603 // 1 extra day this month
606 if (Time
->Day
> Day
) {