]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/Flush.c
FatPkg: Refine casting expression result to bigger size
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / Flush.c
CommitLineData
cae7420b
DB
1/** @file\r
2 Routines that check references and flush OFiles\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 16#include "Fat.h"\r
b9ec9330 17\r
cae7420b 18/**\r
b9ec9330 19\r
cae7420b 20 Flushes all data associated with the file handle.\r
b9ec9330 21\r
cae7420b
DB
22 @param FHand - Handle to file to flush.\r
23 @param Token - A pointer to the token associated with the transaction.\r
b9ec9330 24\r
cae7420b
DB
25 @retval EFI_SUCCESS - Flushed the file successfully.\r
26 @retval EFI_WRITE_PROTECTED - The volume is read only.\r
27 @retval EFI_ACCESS_DENIED - The file is read only.\r
28 @return Others - Flushing of the file failed.\r
b9ec9330 29\r
cae7420b 30**/\r
b9ec9330
QH
31EFI_STATUS\r
32EFIAPI\r
149d6335
RN
33FatFlushEx (\r
34 IN EFI_FILE_PROTOCOL *FHand,\r
35 IN EFI_FILE_IO_TOKEN *Token\r
b9ec9330 36 )\r
b9ec9330
QH
37{\r
38 FAT_IFILE *IFile;\r
39 FAT_OFILE *OFile;\r
40 FAT_VOLUME *Volume;\r
41 EFI_STATUS Status;\r
149d6335 42 FAT_TASK *Task;\r
b9ec9330
QH
43\r
44 IFile = IFILE_FROM_FHAND (FHand);\r
45 OFile = IFile->OFile;\r
46 Volume = OFile->Volume;\r
149d6335 47 Task = NULL;\r
b9ec9330
QH
48\r
49 //\r
50 // If the file has a permanent error, return it\r
51 //\r
52 if (EFI_ERROR (OFile->Error)) {\r
53 return OFile->Error;\r
54 }\r
55\r
56 if (Volume->ReadOnly) {\r
57 return EFI_WRITE_PROTECTED;\r
58 }\r
59 //\r
60 // If read only, return error\r
61 //\r
62 if (IFile->ReadOnly) {\r
63 return EFI_ACCESS_DENIED;\r
64 }\r
149d6335
RN
65\r
66 if (Token == NULL) {\r
67 FatWaitNonblockingTask (IFile);\r
68 } else {\r
69 //\r
70 // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.\r
71 // But if it calls, the below check can avoid crash.\r
72 //\r
73 if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {\r
74 return EFI_UNSUPPORTED;\r
75 }\r
76 Task = FatCreateTask (IFile, Token);\r
77 if (Task == NULL) {\r
78 return EFI_OUT_OF_RESOURCES;\r
79 }\r
80 }\r
81\r
b9ec9330
QH
82 //\r
83 // Flush the OFile\r
84 //\r
85 FatAcquireLock ();\r
86 Status = FatOFileFlush (OFile);\r
149d6335 87 Status = FatCleanupVolume (OFile->Volume, OFile, Status, Task);\r
b9ec9330 88 FatReleaseLock ();\r
149d6335
RN
89\r
90 if (Token != NULL) {\r
91 if (!EFI_ERROR (Status)) {\r
92 Status = FatQueueTask (IFile, Task);\r
93 } else {\r
94 FatDestroyTask (Task);\r
95 }\r
96 }\r
97\r
b9ec9330
QH
98 return Status;\r
99}\r
100\r
cae7420b 101/**\r
149d6335
RN
102\r
103 Flushes all data associated with the file handle.\r
104\r
cae7420b 105 @param FHand - Handle to file to flush.\r
149d6335 106\r
cae7420b
DB
107 @retval EFI_SUCCESS - Flushed the file successfully.\r
108 @retval EFI_WRITE_PROTECTED - The volume is read only.\r
109 @retval EFI_ACCESS_DENIED - The file is read only.\r
110 @return Others - Flushing of the file failed.\r
149d6335 111\r
cae7420b 112**/\r
b9ec9330
QH
113EFI_STATUS\r
114EFIAPI\r
cae7420b 115FatFlush (\r
dba03ba1 116 IN EFI_FILE_PROTOCOL *FHand\r
b9ec9330 117 )\r
cae7420b
DB
118{\r
119 return FatFlushEx (FHand, NULL);\r
120}\r
b9ec9330 121\r
cae7420b 122/**\r
b9ec9330
QH
123\r
124 Flushes & Closes the file handle.\r
125\r
cae7420b 126 @param FHand - Handle to the file to delete.\r
b9ec9330 127\r
cae7420b 128 @retval EFI_SUCCESS - Closed the file successfully.\r
b9ec9330 129\r
cae7420b
DB
130**/\r
131EFI_STATUS\r
132EFIAPI\r
133FatClose (\r
134 IN EFI_FILE_PROTOCOL *FHand\r
135 )\r
b9ec9330
QH
136{\r
137 FAT_IFILE *IFile;\r
138 FAT_OFILE *OFile;\r
139 FAT_VOLUME *Volume;\r
140\r
141 IFile = IFILE_FROM_FHAND (FHand);\r
142 OFile = IFile->OFile;\r
143 Volume = OFile->Volume;\r
144\r
145 //\r
146 // Lock the volume\r
147 //\r
148 FatAcquireLock ();\r
149\r
150 //\r
151 // Close the file instance handle\r
152 //\r
153 FatIFileClose (IFile);\r
154\r
155 //\r
156 // Done. Unlock the volume\r
157 //\r
149d6335 158 FatCleanupVolume (Volume, OFile, EFI_SUCCESS, NULL);\r
b9ec9330
QH
159 FatReleaseLock ();\r
160\r
161 //\r
162 // Close always succeed\r
163 //\r
164 return EFI_SUCCESS;\r
165}\r
166\r
cae7420b 167/**\r
b9ec9330
QH
168\r
169 Close the open file instance.\r
170\r
cae7420b 171 @param IFile - Open file instance.\r
b9ec9330 172\r
cae7420b 173 @retval EFI_SUCCESS - Closed the file successfully.\r
b9ec9330 174\r
cae7420b
DB
175**/\r
176EFI_STATUS\r
177FatIFileClose (\r
178 FAT_IFILE *IFile\r
179 )\r
b9ec9330
QH
180{\r
181 FAT_OFILE *OFile;\r
182 FAT_VOLUME *Volume;\r
183\r
184 OFile = IFile->OFile;\r
185 Volume = OFile->Volume;\r
186\r
187 ASSERT_VOLUME_LOCKED (Volume);\r
188\r
149d6335
RN
189 FatWaitNonblockingTask (IFile);\r
190\r
b9ec9330
QH
191 //\r
192 // Remove the IFile struct\r
193 //\r
194 RemoveEntryList (&IFile->Link);\r
195\r
196 //\r
197 // Add the OFile to the check reference list\r
198 //\r
199 if (OFile->CheckLink.ForwardLink == NULL) {\r
200 InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);\r
201 }\r
202 //\r
203 // Done. Free the open instance structure\r
204 //\r
205 FreePool (IFile);\r
206 return EFI_SUCCESS;\r
207}\r
208\r
cae7420b 209/**\r
b9ec9330
QH
210\r
211 Flush the data associated with an open file.\r
212 In this implementation, only last Mod/Access time is updated.\r
213\r
cae7420b 214 @param OFile - The open file.\r
b9ec9330 215\r
cae7420b
DB
216 @retval EFI_SUCCESS - The OFile is flushed successfully.\r
217 @return Others - An error occurred when flushing this OFile.\r
b9ec9330 218\r
cae7420b
DB
219**/\r
220EFI_STATUS\r
221FatOFileFlush (\r
222 IN FAT_OFILE *OFile\r
223 )\r
b9ec9330
QH
224{\r
225 EFI_STATUS Status;\r
226 FAT_OFILE *Parent;\r
227 FAT_DIRENT *DirEnt;\r
228 FAT_DATE_TIME FatNow;\r
229\r
230 //\r
231 // Flush each entry up the tree while dirty\r
232 //\r
233 do {\r
234 //\r
235 // If the file has a permanant error, then don't write any\r
236 // of its data to the device (may be from different media)\r
237 //\r
238 if (EFI_ERROR (OFile->Error)) {\r
239 return OFile->Error;\r
240 }\r
241\r
242 Parent = OFile->Parent;\r
243 DirEnt = OFile->DirEnt;\r
244 if (OFile->Dirty) {\r
245 //\r
246 // Update the last modification time\r
247 //\r
248 FatGetCurrentFatTime (&FatNow);\r
249 CopyMem (&DirEnt->Entry.FileLastAccess, &FatNow.Date, sizeof (FAT_DATE));\r
250 if (!OFile->PreserveLastModification) {\r
251 FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime);\r
252 }\r
253\r
254 OFile->PreserveLastModification = FALSE;\r
255 if (OFile->Archive) {\r
256 DirEnt->Entry.Attributes |= FAT_ATTRIBUTE_ARCHIVE;\r
257 OFile->Archive = FALSE;\r
258 }\r
259 //\r
260 // Write the directory entry\r
261 //\r
262 if (Parent != NULL && !DirEnt->Invalid) {\r
263 //\r
264 // Write the OFile's directory entry\r
265 //\r
266 Status = FatStoreDirEnt (Parent, DirEnt);\r
267 if (EFI_ERROR (Status)) {\r
268 return Status;\r
269 }\r
270 }\r
271\r
272 OFile->Dirty = FALSE;\r
273 }\r
274 //\r
275 // Check the parent\r
276 //\r
277 OFile = Parent;\r
278 } while (OFile != NULL);\r
279 return EFI_SUCCESS;\r
280}\r
281\r
cae7420b 282/**\r
b9ec9330
QH
283\r
284 Check the references of the OFile.\r
285 If the OFile (that is checked) is no longer\r
286 referenced, then it is freed.\r
287\r
cae7420b 288 @param OFile - The OFile to be checked.\r
b9ec9330 289\r
cae7420b
DB
290 @retval TRUE - The OFile is not referenced and freed.\r
291 @retval FALSE - The OFile is kept.\r
b9ec9330 292\r
cae7420b
DB
293**/\r
294BOOLEAN\r
295FatCheckOFileRef (\r
296 IN FAT_OFILE *OFile\r
297 )\r
b9ec9330
QH
298{\r
299 //\r
300 // If the OFile is on the check ref list, remove it\r
301 //\r
302 if (OFile->CheckLink.ForwardLink != NULL) {\r
303 RemoveEntryList (&OFile->CheckLink);\r
304 OFile->CheckLink.ForwardLink = NULL;\r
305 }\r
306\r
307 FatOFileFlush (OFile);\r
308 //\r
309 // Are there any references to this OFile?\r
310 //\r
311 if (!IsListEmpty (&OFile->Opens) || !IsListEmpty (&OFile->ChildHead)) {\r
312 //\r
313 // The OFile cannot be freed\r
314 //\r
315 return FALSE;\r
316 }\r
317 //\r
318 // Free the Ofile\r
319 //\r
320 FatCloseDirEnt (OFile->DirEnt);\r
321 return TRUE;\r
322}\r
323\r
cae7420b 324/**\r
b9ec9330
QH
325\r
326 Check the references of all open files on the volume.\r
327 Any open file (that is checked) that is no longer\r
328 referenced, is freed - and it's parent open file\r
329 is then referenced checked.\r
330\r
cae7420b 331 @param Volume - The volume to check the pending open file list.\r
b9ec9330 332\r
cae7420b
DB
333**/\r
334STATIC\r
335VOID\r
336FatCheckVolumeRef (\r
337 IN FAT_VOLUME *Volume\r
338 )\r
b9ec9330
QH
339{\r
340 FAT_OFILE *OFile;\r
341 FAT_OFILE *Parent;\r
342\r
343 //\r
344 // Check all files on the pending check list\r
345 //\r
346 while (!IsListEmpty (&Volume->CheckRef)) {\r
347 //\r
348 // Start with the first file listed\r
349 //\r
350 Parent = OFILE_FROM_CHECKLINK (Volume->CheckRef.ForwardLink);\r
351 //\r
352 // Go up the tree cleaning up any un-referenced OFiles\r
353 //\r
354 while (Parent != NULL) {\r
355 OFile = Parent;\r
356 Parent = OFile->Parent;\r
357 if (!FatCheckOFileRef (OFile)) {\r
358 break;\r
359 }\r
360 }\r
361 }\r
362}\r
363\r
cae7420b 364/**\r
b9ec9330
QH
365\r
366 Set error status for a specific OFile, reference checking the volume.\r
367 If volume is already marked as invalid, and all resources are freed\r
368 after reference checking, the file system protocol is uninstalled and\r
369 the volume structure is freed.\r
370\r
cae7420b
DB
371 @param Volume - the Volume that is to be reference checked and unlocked.\r
372 @param OFile - the OFile whose permanent error code is to be set.\r
373 @param EfiStatus - error code to be set.\r
374 @param Task point to task instance.\r
b9ec9330 375\r
cae7420b
DB
376 @retval EFI_SUCCESS - Clean up the volume successfully.\r
377 @return Others - Cleaning up of the volume is failed.\r
b9ec9330 378\r
cae7420b
DB
379**/\r
380EFI_STATUS\r
381FatCleanupVolume (\r
382 IN FAT_VOLUME *Volume,\r
383 IN FAT_OFILE *OFile,\r
384 IN EFI_STATUS EfiStatus,\r
385 IN FAT_TASK *Task\r
386 )\r
b9ec9330
QH
387{\r
388 EFI_STATUS Status;\r
389 //\r
390 // Flag the OFile\r
391 //\r
392 if (OFile != NULL) {\r
393 FatSetVolumeError (OFile, EfiStatus);\r
394 }\r
395 //\r
396 // Clean up any dangling OFiles that don't have IFiles\r
397 // we don't check return status here because we want the\r
398 // volume be cleaned up even the volume is invalid.\r
399 //\r
400 FatCheckVolumeRef (Volume);\r
401 if (Volume->Valid) {\r
402 //\r
403 // Update the free hint info. Volume->FreeInfoPos != 0\r
404 // indicates this a FAT32 volume\r
405 //\r
406 if (Volume->FreeInfoValid && Volume->FatDirty && Volume->FreeInfoPos) {\r
c1680e88 407 Status = FatDiskIo (Volume, WriteDisk, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, Task);\r
b9ec9330
QH
408 if (EFI_ERROR (Status)) {\r
409 return Status;\r
410 }\r
411 }\r
412 //\r
413 // Update that the volume is not dirty\r
414 //\r
c1680e88 415 if (Volume->FatDirty && Volume->FatType != Fat12) {\r
b9ec9330 416 Volume->FatDirty = FALSE;\r
c1680e88 417 Status = FatAccessVolumeDirty (Volume, WriteFat, &Volume->NotDirtyValue);\r
b9ec9330
QH
418 if (EFI_ERROR (Status)) {\r
419 return Status;\r
420 }\r
421 }\r
422 //\r
423 // Flush all dirty cache entries to disk\r
424 //\r
149d6335 425 Status = FatVolumeFlushCache (Volume, Task);\r
b9ec9330
QH
426 if (EFI_ERROR (Status)) {\r
427 return Status;\r
428 }\r
429 }\r
430 //\r
431 // If the volume is cleared , remove it.\r
432 // The only time volume be invalidated is in DriverBindingStop.\r
433 //\r
434 if (Volume->Root == NULL && !Volume->Valid) {\r
435 //\r
436 // Free the volume structure\r
437 //\r
438 FatFreeVolume (Volume);\r
439 }\r
440\r
441 return EfiStatus;\r
442}\r
443\r
cae7420b
DB
444/**\r
445\r
446 Set the OFile and its child OFile with the error Status\r
447\r
448 @param OFile - The OFile whose permanent error code is to be set.\r
449 @param Status - Error code to be set.\r
450\r
451**/\r
b9ec9330
QH
452VOID\r
453FatSetVolumeError (\r
454 IN FAT_OFILE *OFile,\r
455 IN EFI_STATUS Status\r
456 )\r
b9ec9330
QH
457{\r
458 LIST_ENTRY *Link;\r
459 FAT_OFILE *ChildOFile;\r
460\r
461 //\r
462 // If this OFile doesn't already have an error, set one\r
463 //\r
464 if (!EFI_ERROR (OFile->Error)) {\r
465 OFile->Error = Status;\r
466 }\r
467 //\r
468 // Set the error on each child OFile\r
469 //\r
470 for (Link = OFile->ChildHead.ForwardLink; Link != &OFile->ChildHead; Link = Link->ForwardLink) {\r
471 ChildOFile = OFILE_FROM_CHILDLINK (Link);\r
472 FatSetVolumeError (ChildOFile, Status);\r
473 }\r
474}\r