]>
git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/EnhancedFatDxe/Misc.c
3 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Miscellaneous functions
30 EFI_FILE_IO_TOKEN
*Token
40 IFile - The instance of the open file.
41 Token - A pointer to the token associated with the transaction.
44 FAT_TASK * - Return the task instance.
49 Task
= AllocateZeroPool (sizeof (*Task
));
51 Task
->Signature
= FAT_TASK_SIGNATURE
;
53 Task
->FileIoToken
= Token
;
54 InitializeListHead (&Task
->Subtasks
);
55 InitializeListHead (&Task
->Link
);
72 Task - The task to be destroyed.
78 Link
= GetFirstNode (&Task
->Subtasks
);
79 while (!IsNull (&Task
->Subtasks
, Link
)) {
80 Subtask
= CR (Link
, FAT_SUBTASK
, Link
, FAT_SUBTASK_SIGNATURE
);
81 Link
= FatDestroySubtask (Subtask
);
87 FatWaitNonblockingTask (
94 Wait all non-blocking requests complete.
98 IFile - The instance of the open file.
101 BOOLEAN TaskQueueEmpty
;
104 EfiAcquireLock (&FatTaskLock
);
105 TaskQueueEmpty
= IsListEmpty (&IFile
->Tasks
);
106 EfiReleaseLock (&FatTaskLock
);
107 } while (!TaskQueueEmpty
);
118 Remove the subtask from subtask list.
122 Subtask - The subtask to be removed.
126 LIST_ENTRY * - The next node in the list.
132 gBS
->CloseEvent (Subtask
->DiskIo2Token
.Event
);
134 Link
= RemoveEntryList (&Subtask
->Link
);
153 IFile - The instance of the open file.
154 Task - The task to be executed.
158 EFI_SUCCESS - The task was executed sucessfully.
159 other - An error occurred when executing the task.
165 FAT_SUBTASK
*Subtask
;
168 // Sometimes the Task doesn't contain any subtasks, signal the event directly.
170 if (IsListEmpty (&Task
->Subtasks
)) {
171 Task
->FileIoToken
->Status
= EFI_SUCCESS
;
172 gBS
->SignalEvent (Task
->FileIoToken
->Event
);
177 EfiAcquireLock (&FatTaskLock
);
178 InsertTailList (&IFile
->Tasks
, &Task
->Link
);
179 EfiReleaseLock (&FatTaskLock
);
181 Status
= EFI_SUCCESS
;
182 for ( Link
= GetFirstNode (&Task
->Subtasks
)
183 ; !IsNull (&Task
->Subtasks
, Link
)
184 ; Link
= GetNextNode (&Task
->Subtasks
, Link
)
186 Subtask
= CR (Link
, FAT_SUBTASK
, Link
, FAT_SUBTASK_SIGNATURE
);
187 if (Subtask
->Write
) {
189 Status
= IFile
->OFile
->Volume
->DiskIo2
->WriteDiskEx (
190 IFile
->OFile
->Volume
->DiskIo2
,
191 IFile
->OFile
->Volume
->MediaId
,
193 &Subtask
->DiskIo2Token
,
198 Status
= IFile
->OFile
->Volume
->DiskIo2
->ReadDiskEx (
199 IFile
->OFile
->Volume
->DiskIo2
,
200 IFile
->OFile
->Volume
->MediaId
,
202 &Subtask
->DiskIo2Token
,
207 if (EFI_ERROR (Status
)) {
212 if (EFI_ERROR (Status
)) {
213 EfiAcquireLock (&FatTaskLock
);
215 // Remove all the remaining subtasks when failure.
216 // We shouldn't remove all the tasks because the non-blocking requests have
217 // been submitted and cannot be canceled.
219 while (!IsNull (&Task
->Subtasks
, Link
)) {
220 Subtask
= CR (Link
, FAT_SUBTASK
, Link
, FAT_SUBTASK_SIGNATURE
);
221 Link
= FatDestroySubtask (Subtask
);
224 if (IsListEmpty (&Task
->Subtasks
)) {
225 RemoveEntryList (&Task
->Link
);
229 // If one or more subtasks have been already submitted, set FileIoToken
230 // to NULL so that the callback won't signal the event.
232 Task
->FileIoToken
= NULL
;
235 EfiReleaseLock (&FatTaskLock
);
242 FatAccessVolumeDirty (
243 IN FAT_VOLUME
*Volume
,
251 Set the volume as dirty or not
255 Volume - FAT file system volume.
256 IoMode - The access mode.
257 DirtyValue - Set the volume as dirty or not.
261 EFI_SUCCESS - Set the new FAT entry value sucessfully.
262 other - An error occurred when operation the FAT entries.
268 WriteCount
= Volume
->FatEntrySize
;
269 return FatDiskIo (Volume
, IoMode
, Volume
->FatPos
+ WriteCount
, WriteCount
, DirtyValue
, NULL
);
273 Invoke a notification event
275 @param Event Event whose notification function is being invoked.
276 @param Context The pointer to the notification function's context,
277 which is implementation-dependent.
282 FatOnAccessComplete (
290 Invoke a notification event
291 case #1. some subtasks are not completed when the FatOpenEx checks the Task->Subtasks
292 - sets Task->SubtaskCollected so callback to signal the event and free the task.
293 case #2. all subtasks are completed when the FatOpenEx checks the Task->Subtasks
294 - FatOpenEx signal the event and free the task.
297 Event - Event whose notification function is being invoked.
298 Context - The pointer to the notification function's context,
299 which is implementation-dependent.
304 FAT_SUBTASK
*Subtask
;
308 // Avoid someone in future breaks the below assumption.
310 ASSERT (EfiGetCurrentTpl () == FatTaskLock
.Tpl
);
312 Subtask
= (FAT_SUBTASK
*) Context
;
313 Task
= Subtask
->Task
;
314 Status
= Subtask
->DiskIo2Token
.TransactionStatus
;
316 ASSERT (Task
->Signature
== FAT_TASK_SIGNATURE
);
317 ASSERT (Subtask
->Signature
== FAT_SUBTASK_SIGNATURE
);
320 // Remove the task unconditionally
322 FatDestroySubtask (Subtask
);
325 // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory).
327 if (Task
->FileIoToken
!= NULL
) {
328 if (IsListEmpty (&Task
->Subtasks
) || EFI_ERROR (Status
)) {
329 Task
->FileIoToken
->Status
= Status
;
330 gBS
->SignalEvent (Task
->FileIoToken
->Event
);
332 // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored.
334 Task
->FileIoToken
= NULL
;
338 if (IsListEmpty (&Task
->Subtasks
)) {
339 RemoveEntryList (&Task
->Link
);
346 IN FAT_VOLUME
*Volume
,
357 General disk access function
361 Volume - FAT file system volume.
362 IoMode - The access mode (disk read/write or cache access).
363 Offset - The starting byte offset to read from.
364 BufferSize - Size of Buffer.
365 Buffer - Buffer containing read data.
369 EFI_SUCCESS - The operation is performed successfully.
370 EFI_VOLUME_CORRUPTED - The accesss is
371 Others - The status of read/write the disk
376 EFI_DISK_IO_PROTOCOL
*DiskIo
;
377 EFI_DISK_READ IoFunction
;
378 FAT_SUBTASK
*Subtask
;
381 // Verify the IO is in devices range
383 Status
= EFI_VOLUME_CORRUPTED
;
384 if (Offset
+ BufferSize
<= Volume
->VolumeSize
) {
385 if (CACHE_ENABLED (IoMode
)) {
389 Status
= FatAccessCache (Volume
, CACHE_TYPE (IoMode
), RAW_ACCESS (IoMode
), Offset
, BufferSize
, Buffer
, Task
);
392 // Access disk directly
398 DiskIo
= Volume
->DiskIo
;
399 IoFunction
= (IoMode
== READ_DISK
) ? DiskIo
->ReadDisk
: DiskIo
->WriteDisk
;
400 Status
= IoFunction (DiskIo
, Volume
->MediaId
, Offset
, BufferSize
, Buffer
);
403 // Non-blocking access
405 Subtask
= AllocateZeroPool (sizeof (*Subtask
));
406 if (Subtask
== NULL
) {
407 Status
= EFI_OUT_OF_RESOURCES
;
409 Subtask
->Signature
= FAT_SUBTASK_SIGNATURE
;
410 Subtask
->Task
= Task
;
411 Subtask
->Write
= (BOOLEAN
) (IoMode
== WRITE_DISK
);
412 Subtask
->Offset
= Offset
;
413 Subtask
->Buffer
= Buffer
;
414 Subtask
->BufferSize
= BufferSize
;
415 Status
= gBS
->CreateEvent (
420 &Subtask
->DiskIo2Token
.Event
422 if (!EFI_ERROR (Status
)) {
423 InsertTailList (&Task
->Subtasks
, &Subtask
->Link
);
432 if (EFI_ERROR (Status
)) {
433 Volume
->DiskError
= TRUE
;
434 DEBUG ((EFI_D_ERROR
, "FatDiskIo: error %r\n", Status
));
460 EfiAcquireLock (&FatFsLock
);
464 FatAcquireLockOrFail (
472 If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
473 Otherwise, EFI_SUCCESS is returned.
481 EFI_SUCCESS - The volume is locked.
482 EFI_ACCESS_DENIED - The volume could not be locked because it is already locked.
486 return EfiAcquireLockOrFail (&FatFsLock
);
509 EfiReleaseLock (&FatFsLock
);
514 IN FAT_DIRENT
*DirEnt
520 Free directory entry.
524 DirEnt - The directory entry to be freed.
532 if (DirEnt
->FileString
!= NULL
) {
533 FreePool (DirEnt
->FileString
);
541 IN FAT_VOLUME
*Volume
547 Free volume structure (including the contents of directory cache and disk cache).
551 Volume - The volume structure to be freed.
562 if (Volume
->CacheBuffer
!= NULL
) {
563 FreePool (Volume
->CacheBuffer
);
566 // Free directory cache
568 FatCleanupODirCache (Volume
);
573 FatEfiTimeToFatTime (
575 OUT FAT_DATE_TIME
*FTime
581 Translate EFI time to FAT time.
585 ETime - The time of EFI_TIME.
586 FTime - The time of FAT_DATE_TIME.
595 // ignores timezone info in source ETime
597 if (ETime
->Year
> 1980) {
598 FTime
->Date
.Year
= (UINT16
) (ETime
->Year
- 1980);
601 if (ETime
->Year
>= 1980 + FAT_MAX_YEAR_FROM_1980
) {
602 FTime
->Date
.Year
= FAT_MAX_YEAR_FROM_1980
;
605 FTime
->Date
.Month
= ETime
->Month
;
606 FTime
->Date
.Day
= ETime
->Day
;
607 FTime
->Time
.Hour
= ETime
->Hour
;
608 FTime
->Time
.Minute
= ETime
->Minute
;
609 FTime
->Time
.DoubleSecond
= (UINT16
) (ETime
->Second
/ 2);
613 FatFatTimeToEfiTime (
614 IN FAT_DATE_TIME
*FTime
,
621 Translate Fat time to EFI time.
625 FTime - The time of FAT_DATE_TIME.
626 ETime - The time of EFI_TIME.
634 ETime
->Year
= (UINT16
) (FTime
->Date
.Year
+ 1980);
635 ETime
->Month
= (UINT8
) FTime
->Date
.Month
;
636 ETime
->Day
= (UINT8
) FTime
->Date
.Day
;
637 ETime
->Hour
= (UINT8
) FTime
->Time
.Hour
;
638 ETime
->Minute
= (UINT8
) FTime
->Time
.Minute
;
639 ETime
->Second
= (UINT8
) (FTime
->Time
.DoubleSecond
* 2);
640 ETime
->Nanosecond
= 0;
641 ETime
->TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
646 FatGetCurrentFatTime (
647 OUT FAT_DATE_TIME
*FatNow
653 Get Current FAT time.
657 FatNow - Current FAT time.
668 Status
= gRT
->GetTime (&Now
, NULL
);
669 if (!EFI_ERROR (Status
)) {
670 FatEfiTimeToFatTime (&Now
, FatNow
);
672 ZeroMem (&Now
, sizeof (EFI_TIME
));
676 FatEfiTimeToFatTime (&Now
, FatNow
);
688 Check whether a time is valid.
692 Time - The time of EFI_TIME.
696 TRUE - The time is valid.
697 FALSE - The time is not valid.
701 static UINT8 MonthDays
[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
708 // Check the fields for range problems
709 // Fat can only support from 1980
711 if (Time
->Year
< 1980 ||
719 Time
->Nanosecond
> 999999999
726 // Perform a more specific check of the day of the month
728 Day
= MonthDays
[Time
->Month
- 1];
729 if (Time
->Month
== 2 && IS_LEAP_YEAR (Time
->Year
)) {
732 // 1 extra day this month
735 if (Time
->Day
> Day
) {