ReadWrite.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. /** @file
  2. Functions that perform file read/write.
  3. Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "Fat.h"
  7. /**
  8. Get the file's position of the file.
  9. @param FHand - The handle of file.
  10. @param Position - The file's position of the file.
  11. @retval EFI_SUCCESS - Get the info successfully.
  12. @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
  13. @retval EFI_UNSUPPORTED - The open file is not a file.
  14. **/
  15. EFI_STATUS
  16. EFIAPI
  17. FatGetPosition (
  18. IN EFI_FILE_PROTOCOL *FHand,
  19. OUT UINT64 *Position
  20. )
  21. {
  22. FAT_IFILE *IFile;
  23. FAT_OFILE *OFile;
  24. IFile = IFILE_FROM_FHAND (FHand);
  25. OFile = IFile->OFile;
  26. if (OFile->Error == EFI_NOT_FOUND) {
  27. return EFI_DEVICE_ERROR;
  28. }
  29. if (OFile->ODir != NULL) {
  30. return EFI_UNSUPPORTED;
  31. }
  32. *Position = IFile->Position;
  33. return EFI_SUCCESS;
  34. }
  35. /**
  36. Set the file's position of the file.
  37. @param FHand - The handle of file.
  38. @param Position - The file's position of the file.
  39. @retval EFI_SUCCESS - Set the info successfully.
  40. @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
  41. @retval EFI_UNSUPPORTED - Set a directory with a not-zero position.
  42. **/
  43. EFI_STATUS
  44. EFIAPI
  45. FatSetPosition (
  46. IN EFI_FILE_PROTOCOL *FHand,
  47. IN UINT64 Position
  48. )
  49. {
  50. FAT_IFILE *IFile;
  51. FAT_OFILE *OFile;
  52. IFile = IFILE_FROM_FHAND (FHand);
  53. OFile = IFile->OFile;
  54. if (OFile->Error == EFI_NOT_FOUND) {
  55. return EFI_DEVICE_ERROR;
  56. }
  57. FatWaitNonblockingTask (IFile);
  58. //
  59. // If this is a directory, we can only set back to position 0
  60. //
  61. if (OFile->ODir != NULL) {
  62. if (Position != 0) {
  63. //
  64. // Reset current directory cursor;
  65. //
  66. return EFI_UNSUPPORTED;
  67. }
  68. FatResetODirCursor (OFile);
  69. }
  70. //
  71. // Set the position
  72. //
  73. if (Position == (UINT64)-1) {
  74. Position = OFile->FileSize;
  75. }
  76. //
  77. // Set the position
  78. //
  79. IFile->Position = Position;
  80. return EFI_SUCCESS;
  81. }
  82. /**
  83. Get the file info from the open file of the IFile into Buffer.
  84. @param IFile - The instance of the open file.
  85. @param BufferSize - Size of Buffer.
  86. @param Buffer - Buffer containing read data.
  87. @retval EFI_SUCCESS - Get the file info successfully.
  88. @retval other - An error occurred when operation the disk.
  89. **/
  90. EFI_STATUS
  91. FatIFileReadDir (
  92. IN FAT_IFILE *IFile,
  93. IN OUT UINTN *BufferSize,
  94. OUT VOID *Buffer
  95. )
  96. {
  97. EFI_STATUS Status;
  98. FAT_OFILE *OFile;
  99. FAT_ODIR *ODir;
  100. FAT_DIRENT *DirEnt;
  101. UINT32 CurrentPos;
  102. OFile = IFile->OFile;
  103. ODir = OFile->ODir;
  104. CurrentPos = ((UINT32) IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY);
  105. //
  106. // We need to relocate the directory
  107. //
  108. if (CurrentPos < ODir->CurrentPos) {
  109. //
  110. // The directory cursor has been modified by another IFile, we reset the cursor
  111. //
  112. FatResetODirCursor (OFile);
  113. }
  114. //
  115. // We seek the next directory entry's position
  116. //
  117. do {
  118. Status = FatGetNextDirEnt (OFile, &DirEnt);
  119. if (EFI_ERROR (Status) || DirEnt == NULL) {
  120. //
  121. // Something error occurred or reach the end of directory,
  122. // return 0 buffersize
  123. //
  124. *BufferSize = 0;
  125. goto Done;
  126. }
  127. } while (ODir->CurrentPos <= CurrentPos);
  128. Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer);
  129. Done:
  130. //
  131. // Update IFile's Position
  132. //
  133. if (!EFI_ERROR (Status)) {
  134. //
  135. // Update IFile->Position, if everything is all right
  136. //
  137. CurrentPos = ODir->CurrentPos;
  138. IFile->Position = CurrentPos * sizeof (FAT_DIRECTORY_ENTRY);
  139. }
  140. return Status;
  141. }
  142. /**
  143. Get the file info from the open file of the IFile into Buffer.
  144. @param FHand - The file handle to access.
  145. @param IoMode - Indicate whether the access mode is reading or writing.
  146. @param BufferSize - Size of Buffer.
  147. @param Buffer - Buffer containing read data.
  148. @param Token - A pointer to the token associated with the transaction.
  149. @retval EFI_SUCCESS - Get the file info successfully.
  150. @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
  151. @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
  152. @retval EFI_WRITE_PROTECTED - The disk is write protect.
  153. @retval EFI_ACCESS_DENIED - The file is read-only.
  154. @return other - An error occurred when operating on the disk.
  155. **/
  156. EFI_STATUS
  157. FatIFileAccess (
  158. IN EFI_FILE_PROTOCOL *FHand,
  159. IN IO_MODE IoMode,
  160. IN OUT UINTN *BufferSize,
  161. IN OUT VOID *Buffer,
  162. IN EFI_FILE_IO_TOKEN *Token
  163. )
  164. {
  165. EFI_STATUS Status;
  166. FAT_IFILE *IFile;
  167. FAT_OFILE *OFile;
  168. FAT_VOLUME *Volume;
  169. UINT64 EndPosition;
  170. FAT_TASK *Task;
  171. IFile = IFILE_FROM_FHAND (FHand);
  172. OFile = IFile->OFile;
  173. Volume = OFile->Volume;
  174. Task = NULL;
  175. //
  176. // Write to a directory is unsupported
  177. //
  178. if ((OFile->ODir != NULL) && (IoMode == WriteData)) {
  179. return EFI_UNSUPPORTED;
  180. }
  181. if (OFile->Error == EFI_NOT_FOUND) {
  182. return EFI_DEVICE_ERROR;
  183. }
  184. if (IoMode == ReadData) {
  185. //
  186. // If position is at EOF, then return device error
  187. //
  188. if (IFile->Position > OFile->FileSize) {
  189. return EFI_DEVICE_ERROR;
  190. }
  191. } else {
  192. //
  193. // Check if the we can write data
  194. //
  195. if (Volume->ReadOnly) {
  196. return EFI_WRITE_PROTECTED;
  197. }
  198. if (IFile->ReadOnly) {
  199. return EFI_ACCESS_DENIED;
  200. }
  201. }
  202. if (Token == NULL) {
  203. FatWaitNonblockingTask (IFile);
  204. } else {
  205. //
  206. // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.
  207. // But if it calls, the below check can avoid crash.
  208. //
  209. if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {
  210. return EFI_UNSUPPORTED;
  211. }
  212. Task = FatCreateTask (IFile, Token);
  213. if (Task == NULL) {
  214. return EFI_OUT_OF_RESOURCES;
  215. }
  216. }
  217. FatAcquireLock ();
  218. Status = OFile->Error;
  219. if (!EFI_ERROR (Status)) {
  220. if (OFile->ODir != NULL) {
  221. //
  222. // Read a directory is supported
  223. //
  224. ASSERT (IoMode == ReadData);
  225. Status = FatIFileReadDir (IFile, BufferSize, Buffer);
  226. OFile = NULL;
  227. } else {
  228. //
  229. // Access a file
  230. //
  231. EndPosition = IFile->Position + *BufferSize;
  232. if (EndPosition > OFile->FileSize) {
  233. //
  234. // The position goes beyond the end of file
  235. //
  236. if (IoMode == ReadData) {
  237. //
  238. // Adjust the actual size read
  239. //
  240. *BufferSize -= (UINTN) EndPosition - OFile->FileSize;
  241. } else {
  242. //
  243. // We expand the file size of OFile
  244. //
  245. Status = FatGrowEof (OFile, EndPosition);
  246. if (EFI_ERROR (Status)) {
  247. //
  248. // Must update the file's info into the file's Directory Entry
  249. // and then flush the dirty cache info into disk.
  250. //
  251. *BufferSize = 0;
  252. FatOFileFlush (OFile);
  253. OFile = NULL;
  254. goto Done;
  255. }
  256. FatUpdateDirEntClusterSizeInfo (OFile);
  257. }
  258. }
  259. Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer, Task);
  260. IFile->Position += *BufferSize;
  261. }
  262. }
  263. if (Token != NULL) {
  264. if (!EFI_ERROR (Status)) {
  265. Status = FatQueueTask (IFile, Task);
  266. } else {
  267. FatDestroyTask (Task);
  268. }
  269. }
  270. Done:
  271. //
  272. // On EFI_SUCCESS case, not calling FatCleanupVolume():
  273. // 1) The Cache flush operation is avoided to enhance
  274. // performance. Caller is responsible to call Flush() when necessary.
  275. // 2) The volume dirty bit is probably set already, and is expected to be
  276. // cleaned in subsequent Flush() or other operations.
  277. // 3) Write operation doesn't affect OFile/IFile structure, so
  278. // Reference checking is not necessary.
  279. //
  280. if (EFI_ERROR (Status)) {
  281. Status = FatCleanupVolume (Volume, OFile, Status, NULL);
  282. }
  283. FatReleaseLock ();
  284. return Status;
  285. }
  286. /**
  287. Get the file info.
  288. @param FHand - The handle of the file.
  289. @param BufferSize - Size of Buffer.
  290. @param Buffer - Buffer containing read data.
  291. @retval EFI_SUCCESS - Get the file info successfully.
  292. @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
  293. @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
  294. @return other - An error occurred when operation the disk.
  295. **/
  296. EFI_STATUS
  297. EFIAPI
  298. FatRead (
  299. IN EFI_FILE_PROTOCOL *FHand,
  300. IN OUT UINTN *BufferSize,
  301. OUT VOID *Buffer
  302. )
  303. {
  304. return FatIFileAccess (FHand, ReadData, BufferSize, Buffer, NULL);
  305. }
  306. /**
  307. Get the file info.
  308. @param FHand - The handle of the file.
  309. @param Token - A pointer to the token associated with the transaction.
  310. @retval EFI_SUCCESS - Get the file info successfully.
  311. @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
  312. @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
  313. @return other - An error occurred when operation the disk.
  314. **/
  315. EFI_STATUS
  316. EFIAPI
  317. FatReadEx (
  318. IN EFI_FILE_PROTOCOL *FHand,
  319. IN OUT EFI_FILE_IO_TOKEN *Token
  320. )
  321. {
  322. return FatIFileAccess (FHand, ReadData, &Token->BufferSize, Token->Buffer, Token);
  323. }
  324. /**
  325. Write the content of buffer into files.
  326. @param FHand - The handle of the file.
  327. @param BufferSize - Size of Buffer.
  328. @param Buffer - Buffer containing write data.
  329. @retval EFI_SUCCESS - Set the file info successfully.
  330. @retval EFI_WRITE_PROTECTED - The disk is write protect.
  331. @retval EFI_ACCESS_DENIED - The file is read-only.
  332. @retval EFI_DEVICE_ERROR - The OFile is not valid.
  333. @retval EFI_UNSUPPORTED - The open file is not a file.
  334. - The writing file size is larger than 4GB.
  335. @return other - An error occurred when operation the disk.
  336. **/
  337. EFI_STATUS
  338. EFIAPI
  339. FatWrite (
  340. IN EFI_FILE_PROTOCOL *FHand,
  341. IN OUT UINTN *BufferSize,
  342. IN VOID *Buffer
  343. )
  344. {
  345. return FatIFileAccess (FHand, WriteData, BufferSize, Buffer, NULL);
  346. }
  347. /**
  348. Get the file info.
  349. @param FHand - The handle of the file.
  350. @param Token - A pointer to the token associated with the transaction.
  351. @retval EFI_SUCCESS - Get the file info successfully.
  352. @retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
  353. @retval EFI_VOLUME_CORRUPTED - The file type of open file is error.
  354. @return other - An error occurred when operation the disk.
  355. **/
  356. EFI_STATUS
  357. EFIAPI
  358. FatWriteEx (
  359. IN EFI_FILE_PROTOCOL *FHand,
  360. IN OUT EFI_FILE_IO_TOKEN *Token
  361. )
  362. {
  363. return FatIFileAccess (FHand, WriteData, &Token->BufferSize, Token->Buffer, Token);
  364. }
  365. /**
  366. This function reads data from a file or writes data to a file.
  367. It uses OFile->PosRem to determine how much data can be accessed in one time.
  368. @param OFile - The open file.
  369. @param IoMode - Indicate whether the access mode is reading or writing.
  370. @param Position - The position where data will be accessed.
  371. @param DataBufferSize - Size of Buffer.
  372. @param UserBuffer - Buffer containing data.
  373. @param Task point to task instance.
  374. @retval EFI_SUCCESS - Access the data successfully.
  375. @return other - An error occurred when operating on the disk.
  376. **/
  377. EFI_STATUS
  378. FatAccessOFile (
  379. IN FAT_OFILE *OFile,
  380. IN IO_MODE IoMode,
  381. IN UINTN Position,
  382. IN OUT UINTN *DataBufferSize,
  383. IN OUT UINT8 *UserBuffer,
  384. IN FAT_TASK *Task
  385. )
  386. {
  387. FAT_VOLUME *Volume;
  388. UINTN Len;
  389. EFI_STATUS Status;
  390. UINTN BufferSize;
  391. BufferSize = *DataBufferSize;
  392. Volume = OFile->Volume;
  393. ASSERT_VOLUME_LOCKED (Volume);
  394. Status = EFI_SUCCESS;
  395. while (BufferSize > 0) {
  396. //
  397. // Seek the OFile to the file position
  398. //
  399. Status = FatOFilePosition (OFile, Position, BufferSize);
  400. if (EFI_ERROR (Status)) {
  401. break;
  402. }
  403. //
  404. // Clip length to block run
  405. //
  406. Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize;
  407. //
  408. // Write the data
  409. //
  410. Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer, Task);
  411. if (EFI_ERROR (Status)) {
  412. break;
  413. }
  414. //
  415. // Data was successfully accessed
  416. //
  417. Position += Len;
  418. UserBuffer += Len;
  419. BufferSize -= Len;
  420. if (IoMode == WriteData) {
  421. OFile->Dirty = TRUE;
  422. OFile->Archive = TRUE;
  423. }
  424. //
  425. // Make sure no outbound occurred
  426. //
  427. ASSERT (Position <= OFile->FileSize);
  428. }
  429. //
  430. // Update the number of bytes accessed
  431. //
  432. *DataBufferSize -= BufferSize;
  433. return Status;
  434. }
  435. /**
  436. Expand OFile by appending zero bytes at the end of OFile.
  437. @param OFile - The open file.
  438. @param ExpandedSize - The number of zero bytes appended at the end of the file.
  439. @retval EFI_SUCCESS - The file is expanded successfully.
  440. @return other - An error occurred when expanding file.
  441. **/
  442. EFI_STATUS
  443. FatExpandOFile (
  444. IN FAT_OFILE *OFile,
  445. IN UINT64 ExpandedSize
  446. )
  447. {
  448. EFI_STATUS Status;
  449. UINTN WritePos;
  450. WritePos = OFile->FileSize;
  451. Status = FatGrowEof (OFile, ExpandedSize);
  452. if (!EFI_ERROR (Status)) {
  453. Status = FatWriteZeroPool (OFile, WritePos);
  454. }
  455. return Status;
  456. }
  457. /**
  458. Write zero pool from the WritePos to the end of OFile.
  459. @param OFile - The open file to write zero pool.
  460. @param WritePos - The number of zero bytes written.
  461. @retval EFI_SUCCESS - Write the zero pool successfully.
  462. @retval EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation.
  463. @return other - An error occurred when writing disk.
  464. **/
  465. EFI_STATUS
  466. FatWriteZeroPool (
  467. IN FAT_OFILE *OFile,
  468. IN UINTN WritePos
  469. )
  470. {
  471. EFI_STATUS Status;
  472. VOID *ZeroBuffer;
  473. UINTN AppendedSize;
  474. UINTN BufferSize;
  475. UINTN WriteSize;
  476. AppendedSize = OFile->FileSize - WritePos;
  477. BufferSize = AppendedSize;
  478. if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) {
  479. //
  480. // If the appended size is larger, maybe we can not allocate the whole
  481. // memory once. So if the growed size is larger than 10M, we just
  482. // allocate 10M memory (one healthy system should have 10M available
  483. // memory), and then write the zerobuffer to the file several times.
  484. //
  485. BufferSize = FAT_MAX_ALLOCATE_SIZE;
  486. }
  487. ZeroBuffer = AllocateZeroPool (BufferSize);
  488. if (ZeroBuffer == NULL) {
  489. return EFI_OUT_OF_RESOURCES;
  490. }
  491. do {
  492. WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize;
  493. AppendedSize -= WriteSize;
  494. Status = FatAccessOFile (OFile, WriteData, WritePos, &WriteSize, ZeroBuffer, NULL);
  495. if (EFI_ERROR (Status)) {
  496. break;
  497. }
  498. WritePos += WriteSize;
  499. } while (AppendedSize > 0);
  500. FreePool (ZeroBuffer);
  501. return Status;
  502. }
  503. /**
  504. Truncate the OFile to smaller file size.
  505. @param OFile - The open file.
  506. @param TruncatedSize - The new file size.
  507. @retval EFI_SUCCESS - The file is truncated successfully.
  508. @return other - An error occurred when truncating file.
  509. **/
  510. EFI_STATUS
  511. FatTruncateOFile (
  512. IN FAT_OFILE *OFile,
  513. IN UINTN TruncatedSize
  514. )
  515. {
  516. OFile->FileSize = TruncatedSize;
  517. return FatShrinkEof (OFile);
  518. }