Flush.c 11 KB

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