]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - FatPkg/EnhancedFatDxe/Flush.c
FatPkg: Refine casting expression result to bigger size
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / Flush.c
... / ...
CommitLineData
1/** @file\r
2 Routines that check references and flush OFiles\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
17\r
18/**\r
19\r
20 Flushes all data associated with the file handle.\r
21\r
22 @param FHand - Handle to file to flush.\r
23 @param Token - A pointer to the token associated with the transaction.\r
24\r
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
29\r
30**/\r
31EFI_STATUS\r
32EFIAPI\r
33FatFlushEx (\r
34 IN EFI_FILE_PROTOCOL *FHand,\r
35 IN EFI_FILE_IO_TOKEN *Token\r
36 )\r
37{\r
38 FAT_IFILE *IFile;\r
39 FAT_OFILE *OFile;\r
40 FAT_VOLUME *Volume;\r
41 EFI_STATUS Status;\r
42 FAT_TASK *Task;\r
43\r
44 IFile = IFILE_FROM_FHAND (FHand);\r
45 OFile = IFile->OFile;\r
46 Volume = OFile->Volume;\r
47 Task = NULL;\r
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
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
82 //\r
83 // Flush the OFile\r
84 //\r
85 FatAcquireLock ();\r
86 Status = FatOFileFlush (OFile);\r
87 Status = FatCleanupVolume (OFile->Volume, OFile, Status, Task);\r
88 FatReleaseLock ();\r
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
98 return Status;\r
99}\r
100\r
101/**\r
102\r
103 Flushes all data associated with the file handle.\r
104\r
105 @param FHand - Handle to file to flush.\r
106\r
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
111\r
112**/\r
113EFI_STATUS\r
114EFIAPI\r
115FatFlush (\r
116 IN EFI_FILE_PROTOCOL *FHand\r
117 )\r
118{\r
119 return FatFlushEx (FHand, NULL);\r
120}\r
121\r
122/**\r
123\r
124 Flushes & Closes the file handle.\r
125\r
126 @param FHand - Handle to the file to delete.\r
127\r
128 @retval EFI_SUCCESS - Closed the file successfully.\r
129\r
130**/\r
131EFI_STATUS\r
132EFIAPI\r
133FatClose (\r
134 IN EFI_FILE_PROTOCOL *FHand\r
135 )\r
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
158 FatCleanupVolume (Volume, OFile, EFI_SUCCESS, NULL);\r
159 FatReleaseLock ();\r
160\r
161 //\r
162 // Close always succeed\r
163 //\r
164 return EFI_SUCCESS;\r
165}\r
166\r
167/**\r
168\r
169 Close the open file instance.\r
170\r
171 @param IFile - Open file instance.\r
172\r
173 @retval EFI_SUCCESS - Closed the file successfully.\r
174\r
175**/\r
176EFI_STATUS\r
177FatIFileClose (\r
178 FAT_IFILE *IFile\r
179 )\r
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
189 FatWaitNonblockingTask (IFile);\r
190\r
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
209/**\r
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
214 @param OFile - The open file.\r
215\r
216 @retval EFI_SUCCESS - The OFile is flushed successfully.\r
217 @return Others - An error occurred when flushing this OFile.\r
218\r
219**/\r
220EFI_STATUS\r
221FatOFileFlush (\r
222 IN FAT_OFILE *OFile\r
223 )\r
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
282/**\r
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
288 @param OFile - The OFile to be checked.\r
289\r
290 @retval TRUE - The OFile is not referenced and freed.\r
291 @retval FALSE - The OFile is kept.\r
292\r
293**/\r
294BOOLEAN\r
295FatCheckOFileRef (\r
296 IN FAT_OFILE *OFile\r
297 )\r
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
324/**\r
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
331 @param Volume - The volume to check the pending open file list.\r
332\r
333**/\r
334STATIC\r
335VOID\r
336FatCheckVolumeRef (\r
337 IN FAT_VOLUME *Volume\r
338 )\r
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
364/**\r
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
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
375\r
376 @retval EFI_SUCCESS - Clean up the volume successfully.\r
377 @return Others - Cleaning up of the volume is failed.\r
378\r
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
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
407 Status = FatDiskIo (Volume, WriteDisk, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, Task);\r
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
415 if (Volume->FatDirty && Volume->FatType != Fat12) {\r
416 Volume->FatDirty = FALSE;\r
417 Status = FatAccessVolumeDirty (Volume, WriteFat, &Volume->NotDirtyValue);\r
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
425 Status = FatVolumeFlushCache (Volume, Task);\r
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
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
452VOID\r
453FatSetVolumeError (\r
454 IN FAT_OFILE *OFile,\r
455 IN EFI_STATUS Status\r
456 )\r
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