ReadWrite.c 14 KB

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