Flush.c 10.0 KB

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