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