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