You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1568 lines
40KB

  1. /* FatLib Library
  2. * Copyright (C) 2012 by William Greiman
  3. *
  4. * This file is part of the FatLib Library
  5. *
  6. * This Library is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This Library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the FatLib Library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. #include "FatFile.h"
  21. #include "FatFileSystem.h"
  22. //------------------------------------------------------------------------------
  23. // Pointer to cwd directory.
  24. FatFile* FatFile::m_cwd = 0;
  25. // Callback function for date/time.
  26. void (*FatFile::m_dateTime)(uint16_t* date, uint16_t* time) = 0;
  27. //------------------------------------------------------------------------------
  28. // Add a cluster to a file.
  29. bool FatFile::addCluster() {
  30. m_flags |= F_FILE_DIR_DIRTY;
  31. return m_vol->allocateCluster(m_curCluster, &m_curCluster);
  32. }
  33. //------------------------------------------------------------------------------
  34. // Add a cluster to a directory file and zero the cluster.
  35. // Return with first block of cluster in the cache.
  36. bool FatFile::addDirCluster() {
  37. uint32_t block;
  38. cache_t* pc;
  39. // max folder size
  40. if (m_fileSize/sizeof(dir_t) >= 0XFFFF) {
  41. DBG_FAIL_MACRO;
  42. goto fail;
  43. }
  44. if (!addCluster()) {
  45. DBG_FAIL_MACRO;
  46. goto fail;
  47. }
  48. block = m_vol->clusterStartBlock(m_curCluster);
  49. pc = m_vol->cacheFetchData(block, FatCache::CACHE_RESERVE_FOR_WRITE);
  50. if (!pc) {
  51. DBG_FAIL_MACRO;
  52. goto fail;
  53. }
  54. memset(pc, 0, 512);
  55. // zero rest of clusters
  56. for (uint8_t i = 1; i < m_vol->blocksPerCluster(); i++) {
  57. if (!m_vol->writeBlock(block + i, pc->data)) {
  58. DBG_FAIL_MACRO;
  59. goto fail;
  60. }
  61. }
  62. // Increase directory file size by cluster size.
  63. m_fileSize += 512UL*m_vol->blocksPerCluster();
  64. // Set position to EOF to avoid inconsistent curCluster/curPosition.
  65. m_curPosition = m_fileSize;
  66. return true;
  67. fail:
  68. return false;
  69. }
  70. //------------------------------------------------------------------------------
  71. // cache a file's directory entry
  72. // return pointer to cached entry or null for failure
  73. dir_t* FatFile::cacheDirEntry(uint8_t action) {
  74. cache_t* pc;
  75. pc = m_vol->cacheFetchData(m_dirBlock, action);
  76. if (!pc) {
  77. DBG_FAIL_MACRO;
  78. goto fail;
  79. }
  80. return pc->dir + (m_dirIndex & 0XF);
  81. fail:
  82. return 0;
  83. }
  84. //------------------------------------------------------------------------------
  85. bool FatFile::close() {
  86. bool rtn = sync();
  87. m_attr = FILE_ATTR_CLOSED;
  88. return rtn;
  89. }
  90. //------------------------------------------------------------------------------
  91. bool FatFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) {
  92. // error if no blocks
  93. if (m_firstCluster == 0) {
  94. DBG_FAIL_MACRO;
  95. goto fail;
  96. }
  97. for (uint32_t c = m_firstCluster; ; c++) {
  98. uint32_t next;
  99. if (!m_vol->fatGet(c, &next)) {
  100. DBG_FAIL_MACRO;
  101. goto fail;
  102. }
  103. // check for contiguous
  104. if (next != (c + 1)) {
  105. // error if not end of chain
  106. if (!m_vol->isEOC(next)) {
  107. DBG_FAIL_MACRO;
  108. goto fail;
  109. }
  110. *bgnBlock = m_vol->clusterStartBlock(m_firstCluster);
  111. *endBlock = m_vol->clusterStartBlock(c)
  112. + m_vol->blocksPerCluster() - 1;
  113. return true;
  114. }
  115. }
  116. fail:
  117. return false;
  118. }
  119. //------------------------------------------------------------------------------
  120. bool FatFile::createContiguous(FatFile* dirFile,
  121. const char* path, uint32_t size) {
  122. uint32_t count;
  123. // don't allow zero length file
  124. if (size == 0) {
  125. DBG_FAIL_MACRO;
  126. goto fail;
  127. }
  128. if (!open(dirFile, path, O_CREAT | O_EXCL | O_RDWR)) {
  129. DBG_FAIL_MACRO;
  130. goto fail;
  131. }
  132. // calculate number of clusters needed
  133. count = ((size - 1) >> (m_vol->clusterSizeShift() + 9)) + 1;
  134. // allocate clusters
  135. if (!m_vol->allocContiguous(count, &m_firstCluster)) {
  136. remove();
  137. DBG_FAIL_MACRO;
  138. goto fail;
  139. }
  140. m_fileSize = size;
  141. // insure sync() will update dir entry
  142. m_flags |= F_FILE_DIR_DIRTY;
  143. return sync();
  144. fail:
  145. return false;
  146. }
  147. //------------------------------------------------------------------------------
  148. bool FatFile::dirEntry(dir_t* dst) {
  149. dir_t* dir;
  150. // Make sure fields on device are correct.
  151. if (!sync()) {
  152. DBG_FAIL_MACRO;
  153. goto fail;
  154. }
  155. // read entry
  156. dir = cacheDirEntry(FatCache::CACHE_FOR_READ);
  157. if (!dir) {
  158. DBG_FAIL_MACRO;
  159. goto fail;
  160. }
  161. // copy to caller's struct
  162. memcpy(dst, dir, sizeof(dir_t));
  163. return true;
  164. fail:
  165. return false;
  166. }
  167. //------------------------------------------------------------------------------
  168. uint8_t FatFile::dirName(const dir_t* dir, char* name) {
  169. uint8_t j = 0;
  170. for (uint8_t i = 0; i < 11; i++) {
  171. if (dir->name[i] == ' ') continue;
  172. if (i == 8) name[j++] = '.';
  173. name[j++] = dir->name[i];
  174. }
  175. name[j] = 0;
  176. return j;
  177. }
  178. //------------------------------------------------------------------------------
  179. int16_t FatFile::fgets(char* str, int16_t num, char* delim) {
  180. char ch;
  181. int16_t n = 0;
  182. int16_t r = -1;
  183. while ((n + 1) < num && (r = read(&ch, 1)) == 1) {
  184. // delete CR
  185. if (ch == '\r') continue;
  186. str[n++] = ch;
  187. if (!delim) {
  188. if (ch == '\n') break;
  189. } else {
  190. if (strchr(delim, ch)) break;
  191. }
  192. }
  193. if (r < 0) {
  194. // read error
  195. return -1;
  196. }
  197. str[n] = '\0';
  198. return n;
  199. }
  200. //------------------------------------------------------------------------------
  201. bool FatFile::getFilename(char* name) {
  202. dir_t* dir;
  203. if (!isOpen()) {
  204. DBG_FAIL_MACRO;
  205. goto fail;
  206. }
  207. if (isRoot()) {
  208. name[0] = '/';
  209. name[1] = '\0';
  210. return true;
  211. }
  212. // cache entry
  213. dir = cacheDirEntry(FatCache::CACHE_FOR_READ);
  214. if (!dir) {
  215. DBG_FAIL_MACRO;
  216. goto fail;
  217. }
  218. // format name
  219. dirName(dir, name);
  220. return true;
  221. fail:
  222. return false;
  223. }
  224. //------------------------------------------------------------------------------
  225. void FatFile::getpos(FatPos_t* pos) {
  226. pos->position = m_curPosition;
  227. pos->cluster = m_curCluster;
  228. }
  229. //------------------------------------------------------------------------------
  230. // format directory name field from a 8.3 name string
  231. bool FatFile::make83Name(const char* str, uint8_t* name, const char** ptr) {
  232. uint8_t c;
  233. uint8_t n = 7; // max index for part before dot
  234. uint8_t i = 0;
  235. // blank fill name and extension
  236. while (i < 11) name[i++] = ' ';
  237. i = 0;
  238. while (*str != '\0' && *str != '/') {
  239. c = *str++;
  240. if (c == '.') {
  241. if (n == 10) {
  242. // only one dot allowed
  243. DBG_FAIL_MACRO;
  244. goto fail;
  245. }
  246. n = 10; // max index for full 8.3 name
  247. i = 8; // place for extension
  248. } else {
  249. // illegal FAT characters
  250. #ifdef __AVR__
  251. // store chars in flash
  252. PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
  253. uint8_t b;
  254. while ((b = pgm_read_byte(p++))) if (b == c) {
  255. DBG_FAIL_MACRO;
  256. goto fail;
  257. }
  258. #else // __AVR__
  259. // store chars in RAM
  260. if (strchr("|<>^+=?/[];,*\"\\", c)) {
  261. DBG_FAIL_MACRO;
  262. goto fail;
  263. }
  264. #endif // __AVR__
  265. // check size and only allow ASCII printable characters
  266. if (i > n || c < 0X21 || c > 0X7E) {
  267. DBG_FAIL_MACRO;
  268. goto fail;
  269. }
  270. // only upper case allowed in 8.3 names - convert lower to upper
  271. name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a');
  272. }
  273. }
  274. *ptr = str;
  275. // must have a file name, extension is optional
  276. return name[0] != ' ';
  277. fail:
  278. return false;
  279. }
  280. //------------------------------------------------------------------------------
  281. bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
  282. uint8_t dname[11];
  283. FatFile tmpDir;
  284. if (isOpen() || !parent->isDir()) {
  285. DBG_FAIL_MACRO;
  286. goto fail;
  287. }
  288. if (*path == '/') {
  289. while (*path == '/') path++;
  290. if (!parent->isRoot()) {
  291. if (!tmpDir.openRoot(parent->m_vol)) {
  292. DBG_FAIL_MACRO;
  293. goto fail;
  294. }
  295. parent = &tmpDir;
  296. }
  297. }
  298. while (1) {
  299. if (!make83Name(path, dname, &path)) {
  300. DBG_FAIL_MACRO;
  301. goto fail;
  302. }
  303. while (*path == '/') path++;
  304. if (!*path) break;
  305. if (!open(parent, dname, O_READ)) {
  306. if (!pFlag || !mkdir(parent, dname)) {
  307. DBG_FAIL_MACRO;
  308. goto fail;
  309. }
  310. }
  311. tmpDir = *this;
  312. parent = &tmpDir;
  313. close();
  314. }
  315. return mkdir(parent, dname);
  316. fail:
  317. return false;
  318. }
  319. //------------------------------------------------------------------------------
  320. bool FatFile::mkdir(FatFile* parent, const uint8_t dname[11]) {
  321. uint32_t block;
  322. dir_t dot;
  323. dir_t* dir;
  324. cache_t* pc;
  325. if (!parent->isDir()) {
  326. DBG_FAIL_MACRO;
  327. goto fail;
  328. }
  329. // create a normal file
  330. if (!open(parent, dname, O_CREAT | O_EXCL | O_RDWR)) {
  331. DBG_FAIL_MACRO;
  332. goto fail;
  333. }
  334. // convert file to directory
  335. m_flags = O_READ;
  336. m_attr = FILE_ATTR_IS_OPEN | FILE_ATTR_SUBDIR;
  337. // allocate and zero first cluster
  338. if (!addDirCluster()) {
  339. DBG_FAIL_MACRO;
  340. goto fail;
  341. }
  342. m_firstCluster = m_curCluster;
  343. // Set to start of dir
  344. rewind();
  345. // force entry to device
  346. if (!sync()) {
  347. DBG_FAIL_MACRO;
  348. goto fail;
  349. }
  350. // cache entry - should already be in cache due to sync() call
  351. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  352. if (!dir) {
  353. DBG_FAIL_MACRO;
  354. goto fail;
  355. }
  356. // change directory entry attribute
  357. dir->attributes = DIR_ATT_DIRECTORY;
  358. // make entry for '.'
  359. memcpy(&dot, dir, sizeof(dot));
  360. dot.name[0] = '.';
  361. for (uint8_t i = 1; i < 11; i++) dot.name[i] = ' ';
  362. // cache block for '.' and '..'
  363. block = m_vol->clusterStartBlock(m_firstCluster);
  364. pc = m_vol->cacheFetchData(block, FatCache::CACHE_FOR_WRITE);
  365. if (!pc) {
  366. DBG_FAIL_MACRO;
  367. goto fail;
  368. }
  369. // copy '.' to block
  370. memcpy(&pc->dir[0], &dot, sizeof(dot));
  371. // make entry for '..'
  372. dot.name[1] = '.';
  373. if (parent->isRoot()) {
  374. dot.firstClusterLow = 0;
  375. dot.firstClusterHigh = 0;
  376. } else {
  377. dot.firstClusterLow = parent->m_firstCluster & 0XFFFF;
  378. dot.firstClusterHigh = parent->m_firstCluster >> 16;
  379. }
  380. // copy '..' to block
  381. memcpy(&pc->dir[1], &dot, sizeof(dot));
  382. // write first block
  383. return m_vol->cacheSync();
  384. fail:
  385. return false;
  386. }
  387. //------------------------------------------------------------------------------
  388. bool FatFile::open(FatFileSystem* fs, const char* path, uint8_t oflag) {
  389. return open(fs->vwd(), path, oflag);
  390. }
  391. //------------------------------------------------------------------------------
  392. bool FatFile::open(FatFile* dirFile, const char* path, uint8_t oflag) {
  393. FatFile tmpDir;
  394. uint8_t dname[11];
  395. // error if already open
  396. if (isOpen() || !dirFile->isDir()) {
  397. DBG_FAIL_MACRO;
  398. goto fail;
  399. }
  400. if (*path == '/') {
  401. while (*path == '/') path++;
  402. if (*path == 0) return openRoot(dirFile->m_vol);
  403. if (!dirFile->isRoot()) {
  404. if (!tmpDir.openRoot(dirFile->m_vol)) {
  405. DBG_FAIL_MACRO;
  406. goto fail;
  407. }
  408. dirFile = &tmpDir;
  409. }
  410. }
  411. while (1) {
  412. if (!make83Name(path, dname, &path)) {
  413. DBG_FAIL_MACRO;
  414. goto fail;
  415. }
  416. while (*path == '/') path++;
  417. if (*path == 0) break;
  418. if (!open(dirFile, dname, O_READ) || !isDir()) {
  419. DBG_FAIL_MACRO;
  420. goto fail;
  421. }
  422. tmpDir = *this;
  423. dirFile = &tmpDir;
  424. close();
  425. }
  426. return open(dirFile, dname, oflag);
  427. fail:
  428. return false;
  429. }
  430. //------------------------------------------------------------------------------
  431. // open with filename in dname
  432. bool FatFile::open(FatFile* dirFile,
  433. const uint8_t dname[11], uint8_t oflag) {
  434. bool emptyFound = false;
  435. bool fileFound = false;
  436. uint16_t emptyIndex;
  437. uint16_t index = 0;
  438. dir_t* dir;
  439. dirFile->rewind();
  440. while (1) {
  441. if (!emptyFound) emptyIndex = index;
  442. if (dirFile->m_curPosition >= dirFile->m_fileSize) break;
  443. if ((0XF & index) == 0) {
  444. dir = dirFile->readDirCache();
  445. if (!dir) {
  446. DBG_FAIL_MACRO;
  447. goto fail;
  448. }
  449. } else {
  450. dirFile->m_curPosition += 32;
  451. dir++;
  452. }
  453. // done if last entry
  454. if (dir->name[0] == DIR_NAME_FREE || dir->name[0] == DIR_NAME_DELETED) {
  455. emptyFound = true;
  456. if (dir->name[0] == DIR_NAME_FREE) break;
  457. } else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
  458. if (!memcmp(dname, dir->name, 11)) {
  459. fileFound = true;
  460. break;
  461. }
  462. }
  463. index++;
  464. }
  465. if (fileFound) {
  466. // don't open existing file if O_EXCL
  467. if (oflag & O_EXCL) {
  468. DBG_FAIL_MACRO;
  469. goto fail;
  470. }
  471. } else {
  472. // don't create unless O_CREAT and O_WRITE
  473. if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) {
  474. DBG_FAIL_MACRO;
  475. goto fail;
  476. }
  477. if (!emptyFound) {
  478. if (dirFile->isRootFixed()) {
  479. DBG_FAIL_MACRO;
  480. goto fail;
  481. }
  482. if (!dirFile->addDirCluster()) {
  483. DBG_FAIL_MACRO;
  484. goto fail;
  485. }
  486. }
  487. index = emptyIndex;
  488. dirFile->seekSet(32UL*index);
  489. dir = dirFile->readDirCache();
  490. if (!dir) {
  491. DBG_FAIL_MACRO;
  492. goto fail;
  493. }
  494. // initialize as empty file
  495. memset(dir, 0, sizeof(dir_t));
  496. memcpy(dir->name, dname, 11);
  497. // set timestamps
  498. if (m_dateTime) {
  499. // call user date/time function
  500. m_dateTime(&dir->creationDate, &dir->creationTime);
  501. } else {
  502. // use default date/time
  503. dir->creationDate = FAT_DEFAULT_DATE;
  504. dir->creationTime = FAT_DEFAULT_TIME;
  505. }
  506. dir->lastAccessDate = dir->creationDate;
  507. dir->lastWriteDate = dir->creationDate;
  508. dir->lastWriteTime = dir->creationTime;
  509. // Force write of entry to device.
  510. dirFile->m_vol->cacheDirty();
  511. }
  512. // open entry in cache
  513. return openCachedEntry(dirFile, index, oflag);
  514. fail:
  515. return false;
  516. }
  517. //------------------------------------------------------------------------------
  518. bool FatFile::open(FatFile* dirFile, uint16_t index, uint8_t oflag) {
  519. dir_t* dir;
  520. // error if already open
  521. if (isOpen() || !dirFile->isDir()) {
  522. DBG_FAIL_MACRO;
  523. goto fail;
  524. }
  525. // don't open existing file if O_EXCL - user call error
  526. if (oflag & O_EXCL) {
  527. DBG_FAIL_MACRO;
  528. goto fail;
  529. }
  530. // seek to location of entry
  531. if (!dirFile->seekSet(32UL * index)) {
  532. DBG_FAIL_MACRO;
  533. goto fail;
  534. }
  535. // read entry into cache
  536. dir = dirFile->readDirCache();
  537. if (!dir) {
  538. DBG_FAIL_MACRO;
  539. goto fail;
  540. }
  541. // error if empty slot or '.' or '..'
  542. if (dir->name[0] == DIR_NAME_FREE ||
  543. dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
  544. DBG_FAIL_MACRO;
  545. goto fail;
  546. }
  547. // open cached entry
  548. return openCachedEntry(dirFile, index, oflag);
  549. fail:
  550. return false;
  551. }
  552. //------------------------------------------------------------------------------
  553. // open a cached directory entry. Assumes m_vol is initialized
  554. bool FatFile::openCachedEntry(FatFile* dirFile,
  555. uint16_t dirIndex, uint8_t oflag) {
  556. // location of entry in cache
  557. m_vol = dirFile->m_vol;
  558. dir_t* dir = &m_vol->cacheAddress()->dir[0XF & dirIndex];
  559. // Must be file or subdirectory.
  560. if (!DIR_IS_FILE_OR_SUBDIR(dir)) {
  561. DBG_FAIL_MACRO;
  562. goto fail;
  563. }
  564. m_attr = FILE_ATTR_IS_OPEN | (dir->attributes & FILE_ATTR_COPY);
  565. // Write or truncate is an error for a directory or read-only file
  566. if (isSubDir() || isReadOnly()) {
  567. if (oflag & (O_WRITE | O_TRUNC)) {
  568. DBG_FAIL_MACRO;
  569. goto fail;
  570. }
  571. }
  572. // remember location of directory entry on device
  573. m_dirFirstCluster = dirFile->m_firstCluster;
  574. m_dirBlock = m_vol->cacheBlockNumber();
  575. m_dirIndex = dirIndex;
  576. // copy first cluster number for directory fields
  577. m_firstCluster = (uint32_t)dir->firstClusterHigh << 16;
  578. m_firstCluster |= dir->firstClusterLow;
  579. // Set file size
  580. if (isSubDir()) {
  581. if (!setDirSize()) {
  582. DBG_FAIL_MACRO;
  583. goto fail;
  584. }
  585. } else {
  586. m_fileSize = dir->fileSize;
  587. }
  588. // save open flags for read/write
  589. m_flags = oflag & F_OFLAG;
  590. // set to start of file
  591. m_curCluster = 0;
  592. m_curPosition = 0;
  593. if ((oflag & O_TRUNC) && !truncate(0)) {
  594. DBG_FAIL_MACRO;
  595. goto fail;
  596. }
  597. return oflag & O_AT_END ? seekEnd(0) : true;
  598. fail:
  599. m_attr = FILE_ATTR_CLOSED;
  600. return false;
  601. }
  602. //------------------------------------------------------------------------------
  603. bool FatFile::openNext(FatFile* dirFile, uint8_t oflag) {
  604. uint16_t index;
  605. // Check for valid directory and file is not open.
  606. if (!dirFile->isDir() || isOpen()) {
  607. DBG_FAIL_MACRO;
  608. goto fail;
  609. }
  610. while (1) {
  611. // Check for EOF.
  612. if (dirFile->curPosition() == dirFile->fileSize()) {
  613. DBG_FAIL_MACRO;
  614. goto fail;
  615. }
  616. // read entry into cache
  617. index = dirFile->curPosition()/32;
  618. dir_t* dir = dirFile->readDirCache();
  619. if (!dir) {
  620. DBG_FAIL_MACRO;
  621. goto fail;
  622. }
  623. // done if last entry
  624. if (dir->name[0] == DIR_NAME_FREE) {
  625. DBG_FAIL_MACRO;
  626. goto fail;
  627. }
  628. // must be file or dir
  629. // skip empty slot or '.' or '..'
  630. if (DIR_IS_FILE_OR_SUBDIR(dir) && dir->name[0] != '.' &&
  631. dir->name[0] != DIR_NAME_DELETED) {
  632. return openCachedEntry(dirFile, index, oflag);
  633. }
  634. }
  635. fail:
  636. return false;
  637. }
  638. //------------------------------------------------------------------------------
  639. /** Open a directory's parent directory.
  640. *
  641. * \param[in] dir Parent of this directory will be opened. Must not be root.
  642. *
  643. * \return The value one, true, is returned for success and
  644. * the value zero, false, is returned for failure.
  645. */
  646. bool FatFile::openParent(FatFile* dirFile) {
  647. dir_t entry;
  648. dir_t* dir;
  649. FatFile file;
  650. uint32_t c;
  651. uint32_t cluster;
  652. uint32_t lbn;
  653. cache_t* pc;
  654. // error if already open or dir is root or dir is not a directory
  655. if (isOpen() || dirFile->isRoot() || !dirFile->isDir()) {
  656. DBG_FAIL_MACRO;
  657. goto fail;
  658. }
  659. m_vol = dirFile->m_vol;
  660. // position to '..'
  661. if (!dirFile->seekSet(32)) {
  662. DBG_FAIL_MACRO;
  663. goto fail;
  664. }
  665. // read '..' entry
  666. if (dirFile->read(&entry, sizeof(entry)) != 32) {
  667. DBG_FAIL_MACRO;
  668. goto fail;
  669. }
  670. // verify it is '..'
  671. if (entry.name[0] != '.' || entry.name[1] != '.') {
  672. DBG_FAIL_MACRO;
  673. goto fail;
  674. }
  675. // start cluster for '..'
  676. cluster = entry.firstClusterLow;
  677. cluster |= (uint32_t)entry.firstClusterHigh << 16;
  678. if (cluster == 0) return openRoot(m_vol);
  679. // start block for '..'
  680. lbn = m_vol->clusterStartBlock(cluster);
  681. // first block of parent dir
  682. pc = m_vol->cacheFetchData(lbn, FatCache::CACHE_FOR_READ);
  683. if (!pc) {
  684. DBG_FAIL_MACRO;
  685. goto fail;
  686. }
  687. dir = &pc->dir[1];
  688. // verify name for '../..'
  689. if (dir->name[0] != '.' || dir->name[1] != '.') {
  690. DBG_FAIL_MACRO;
  691. goto fail;
  692. }
  693. // '..' is pointer to first cluster of parent. open '../..' to find parent
  694. if (dir->firstClusterHigh == 0 && dir->firstClusterLow == 0) {
  695. if (!file.openRoot(dirFile->volume())) {
  696. DBG_FAIL_MACRO;
  697. goto fail;
  698. }
  699. } else {
  700. if (!file.openCachedEntry(dirFile, 1, O_READ)) {
  701. DBG_FAIL_MACRO;
  702. goto fail;
  703. }
  704. }
  705. // search for parent in '../..'
  706. do {
  707. if (file.readDir(&entry) != 32) {
  708. DBG_FAIL_MACRO;
  709. goto fail;
  710. }
  711. c = entry.firstClusterLow;
  712. c |= (uint32_t)entry.firstClusterHigh << 16;
  713. } while (c != cluster);
  714. // open parent
  715. return open(&file, file.curPosition()/32 - 1, O_READ);
  716. fail:
  717. return false;
  718. }
  719. //------------------------------------------------------------------------------
  720. bool FatFile::openRoot(FatVolume* vol) {
  721. // error if file is already open
  722. if (isOpen()) {
  723. DBG_FAIL_MACRO;
  724. goto fail;
  725. }
  726. m_vol = vol;
  727. if (vol->fatType() == 16 || (FAT12_SUPPORT && vol->fatType() == 12)) {
  728. m_attr = FILE_ATTR_IS_OPEN | FILE_ATTR_ROOT_FIXED;
  729. m_firstCluster = 0;
  730. m_fileSize = 32 * vol->rootDirEntryCount();
  731. } else if (vol->fatType() == 32) {
  732. m_attr = FILE_ATTR_IS_OPEN | FILE_ATTR_ROOT32;
  733. m_firstCluster = vol->rootDirStart();
  734. if (!setDirSize()) {
  735. DBG_FAIL_MACRO;
  736. goto fail;
  737. }
  738. } else {
  739. // volume is not initialized, invalid, or FAT12 without support
  740. DBG_FAIL_MACRO;
  741. goto fail;
  742. }
  743. // read only
  744. m_flags = O_READ;
  745. // set to start of file
  746. m_curCluster = 0;
  747. m_curPosition = 0;
  748. // root has no directory entry
  749. m_dirBlock = 0;
  750. m_dirIndex = 0;
  751. return true;
  752. fail:
  753. return false;
  754. }
  755. //------------------------------------------------------------------------------
  756. int FatFile::peek() {
  757. FatPos_t pos;
  758. getpos(&pos);
  759. int c = read();
  760. if (c >= 0) setpos(&pos);
  761. return c;
  762. }
  763. //------------------------------------------------------------------------------
  764. int FatFile::read(void* buf, size_t nbyte) {
  765. uint8_t blockOfCluster;
  766. uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
  767. uint16_t offset;
  768. size_t toRead;
  769. uint32_t block; // raw device block number
  770. cache_t* pc;
  771. // error if not open or write only
  772. if (!isOpen() || !(m_flags & O_READ)) {
  773. DBG_FAIL_MACRO;
  774. goto fail;
  775. }
  776. // max bytes left in file
  777. if (nbyte >= (m_fileSize - m_curPosition)) {
  778. nbyte = m_fileSize - m_curPosition;
  779. }
  780. // amount left to read
  781. toRead = nbyte;
  782. while (toRead > 0) {
  783. size_t n;
  784. offset = m_curPosition & 0X1FF; // offset in block
  785. blockOfCluster = m_vol->blockOfCluster(m_curPosition);
  786. if (isRootFixed()) {
  787. block = m_vol->rootDirStart() + (m_curPosition >> 9);
  788. } else {
  789. if (offset == 0 && blockOfCluster == 0) {
  790. // start of new cluster
  791. if (m_curPosition == 0) {
  792. // use first cluster in file
  793. m_curCluster = m_firstCluster;
  794. } else {
  795. // get next cluster from FAT
  796. if (!m_vol->fatGet(m_curCluster, &m_curCluster)) {
  797. DBG_FAIL_MACRO;
  798. goto fail;
  799. }
  800. }
  801. }
  802. block = m_vol->clusterStartBlock(m_curCluster) + blockOfCluster;
  803. }
  804. if (offset != 0 || toRead < 512 || block == m_vol->cacheBlockNumber()) {
  805. // amount to be read from current block
  806. n = 512 - offset;
  807. if (n > toRead) n = toRead;
  808. // read block to cache and copy data to caller
  809. pc = m_vol->cacheFetchData(block, FatCache::CACHE_FOR_READ);
  810. if (!pc) {
  811. DBG_FAIL_MACRO;
  812. goto fail;
  813. }
  814. uint8_t* src = pc->data + offset;
  815. memcpy(dst, src, n);
  816. #if USE_MULTI_BLOCK_IO
  817. } else if (toRead >= 1024) {
  818. uint8_t nb = toRead >> 9;
  819. if (!isRootFixed()) {
  820. uint8_t mb = m_vol->blocksPerCluster() - blockOfCluster;
  821. if (mb < nb) nb = mb;
  822. }
  823. n = 512*nb;
  824. if (m_vol->cacheBlockNumber() <= block
  825. && block < (m_vol->cacheBlockNumber() + nb)) {
  826. // flush cache if a block is in the cache
  827. if (!m_vol->cacheSync()) {
  828. DBG_FAIL_MACRO;
  829. goto fail;
  830. }
  831. }
  832. if (!m_vol->readBlocks(block, dst, nb)) {
  833. DBG_FAIL_MACRO;
  834. goto fail;
  835. }
  836. #endif // USE_MULTI_BLOCK_IO
  837. } else {
  838. // read single block
  839. n = 512;
  840. if (!m_vol->readBlock(block, dst)) {
  841. DBG_FAIL_MACRO;
  842. goto fail;
  843. }
  844. }
  845. dst += n;
  846. m_curPosition += n;
  847. toRead -= n;
  848. }
  849. return nbyte;
  850. fail:
  851. return -1;
  852. }
  853. //------------------------------------------------------------------------------
  854. int8_t FatFile::readDir(dir_t* dir) {
  855. int16_t n;
  856. // if not a directory file or miss-positioned return an error
  857. if (!isDir() || (0X1F & m_curPosition)) return -1;
  858. while (1) {
  859. n = read(dir, sizeof(dir_t));
  860. if (n != sizeof(dir_t)) return n == 0 ? 0 : -1;
  861. // last entry if DIR_NAME_FREE
  862. if (dir->name[0] == DIR_NAME_FREE) return 0;
  863. // skip empty entries and entry for . and ..
  864. if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue;
  865. // return if normal file or subdirectory
  866. if (DIR_IS_FILE_OR_SUBDIR(dir)) return n;
  867. }
  868. }
  869. //------------------------------------------------------------------------------
  870. // Read next directory entry into the cache
  871. // Assumes file is correctly positioned
  872. dir_t* FatFile::readDirCache() {
  873. uint8_t i;
  874. // index of entry in cache
  875. i = (m_curPosition >> 5) & 0XF;
  876. // use read to locate and cache block
  877. if (read() < 0) {
  878. DBG_FAIL_MACRO;
  879. goto fail;
  880. }
  881. // advance to next entry
  882. m_curPosition += 31;
  883. // return pointer to entry
  884. return m_vol->cacheAddress()->dir + i;
  885. fail:
  886. return 0;
  887. }
  888. //------------------------------------------------------------------------------
  889. bool FatFile::remove() {
  890. dir_t* dir;
  891. // Free any clusters - will fail if read-only or directory.
  892. if (!truncate(0)) {
  893. DBG_FAIL_MACRO;
  894. goto fail;
  895. }
  896. // Cache directory entry.
  897. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  898. if (!dir) {
  899. DBG_FAIL_MACRO;
  900. goto fail;
  901. }
  902. // Mark entry deleted.
  903. dir->name[0] = DIR_NAME_DELETED;
  904. // Set this file closed.
  905. m_attr = FILE_ATTR_CLOSED;
  906. // Write entry to device.
  907. return m_vol->cacheSync();
  908. fail:
  909. return false;
  910. }
  911. //------------------------------------------------------------------------------
  912. bool FatFile::remove(FatFile* dirFile, const char* path) {
  913. FatFile file;
  914. if (!file.open(dirFile, path, O_WRITE)) {
  915. DBG_FAIL_MACRO;
  916. goto fail;
  917. }
  918. return file.remove();
  919. fail:
  920. return false;
  921. }
  922. //------------------------------------------------------------------------------
  923. bool FatFile::rename(FatFile* dirFile, const char* newPath) {
  924. dir_t entry;
  925. uint32_t dirCluster = 0;
  926. FatFile file;
  927. cache_t* pc;
  928. dir_t* dir;
  929. // Must be an open file or subdirectory.
  930. if (!(isFile() || isSubDir())) {
  931. DBG_FAIL_MACRO;
  932. goto fail;
  933. }
  934. // Can't move file to new volume.
  935. if (m_vol != dirFile->m_vol) {
  936. DBG_FAIL_MACRO;
  937. goto fail;
  938. }
  939. // sync() and cache directory entry
  940. sync();
  941. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  942. if (!dir) {
  943. DBG_FAIL_MACRO;
  944. goto fail;
  945. }
  946. // save directory entry
  947. memcpy(&entry, dir, sizeof(entry));
  948. // mark entry deleted
  949. dir->name[0] = DIR_NAME_DELETED;
  950. // make directory entry for new path
  951. if (isFile()) {
  952. if (!file.open(dirFile, newPath, O_CREAT | O_EXCL | O_WRITE)) {
  953. goto restore;
  954. }
  955. } else {
  956. // don't create missing path prefix components
  957. if (!file.mkdir(dirFile, newPath, false)) {
  958. goto restore;
  959. }
  960. // save cluster containing new dot dot
  961. dirCluster = file.m_firstCluster;
  962. }
  963. // change to new directory entry
  964. m_dirBlock = file.m_dirBlock;
  965. m_dirIndex = file.m_dirIndex;
  966. // mark closed to avoid possible destructor close call
  967. file.m_attr = FILE_ATTR_CLOSED;
  968. // cache new directory entry
  969. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  970. if (!dir) {
  971. DBG_FAIL_MACRO;
  972. goto fail;
  973. }
  974. // copy all but name field to new directory entry
  975. memcpy(&dir->attributes, &entry.attributes,
  976. sizeof(entry) - sizeof(dir->name));
  977. // update dot dot if directory
  978. if (dirCluster) {
  979. // get new dot dot
  980. uint32_t block = m_vol->clusterStartBlock(dirCluster);
  981. pc = m_vol->cacheFetchData(block, FatCache::CACHE_FOR_READ);
  982. if (!pc) {
  983. DBG_FAIL_MACRO;
  984. goto fail;
  985. }
  986. memcpy(&entry, &pc->dir[1], sizeof(entry));
  987. // free unused cluster
  988. if (!m_vol->freeChain(dirCluster)) {
  989. DBG_FAIL_MACRO;
  990. goto fail;
  991. }
  992. // store new dot dot
  993. block = m_vol->clusterStartBlock(m_firstCluster);
  994. pc = m_vol->cacheFetchData(block, FatCache::CACHE_FOR_WRITE);
  995. if (!pc) {
  996. DBG_FAIL_MACRO;
  997. goto fail;
  998. }
  999. memcpy(&pc->dir[1], &entry, sizeof(entry));
  1000. }
  1001. return m_vol->cacheSync();
  1002. restore:
  1003. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  1004. if (!dir) {
  1005. DBG_FAIL_MACRO;
  1006. goto fail;
  1007. }
  1008. // restore entry
  1009. dir->name[0] = entry.name[0];
  1010. m_vol->cacheSync();
  1011. fail:
  1012. return false;
  1013. }
  1014. //------------------------------------------------------------------------------
  1015. bool FatFile::rmdir() {
  1016. // must be open subdirectory
  1017. if (!isSubDir()) {
  1018. DBG_FAIL_MACRO;
  1019. goto fail;
  1020. }
  1021. rewind();
  1022. // make sure directory is empty
  1023. while (m_curPosition < m_fileSize) {
  1024. dir_t* dir = readDirCache();
  1025. if (!dir) {
  1026. DBG_FAIL_MACRO;
  1027. goto fail;
  1028. }
  1029. // done if past last used entry
  1030. if (dir->name[0] == DIR_NAME_FREE) break;
  1031. // skip empty slot, '.' or '..'
  1032. if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue;
  1033. // error not empty
  1034. if (DIR_IS_FILE_OR_SUBDIR(dir)) {
  1035. DBG_FAIL_MACRO;
  1036. goto fail;
  1037. }
  1038. }
  1039. // convert empty directory to normal file for remove
  1040. m_attr = FILE_ATTR_IS_OPEN;
  1041. m_flags |= O_WRITE;
  1042. return remove();
  1043. fail:
  1044. return false;
  1045. }
  1046. //------------------------------------------------------------------------------
  1047. bool FatFile::rmRfStar() {
  1048. uint16_t index;
  1049. FatFile f;
  1050. rewind();
  1051. while (m_curPosition < m_fileSize) {
  1052. // remember position
  1053. index = m_curPosition/32;
  1054. dir_t* dir = readDirCache();
  1055. if (!dir) {
  1056. DBG_FAIL_MACRO;
  1057. goto fail;
  1058. }
  1059. // done if past last entry
  1060. if (dir->name[0] == DIR_NAME_FREE) break;
  1061. // skip empty slot or '.' or '..'
  1062. if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue;
  1063. // skip if part of long file name or volume label in root
  1064. if (!DIR_IS_FILE_OR_SUBDIR(dir)) continue;
  1065. if (!f.open(this, index, O_READ)) {
  1066. DBG_FAIL_MACRO;
  1067. goto fail;
  1068. }
  1069. if (f.isSubDir()) {
  1070. // recursively delete
  1071. if (!f.rmRfStar()) {
  1072. DBG_FAIL_MACRO;
  1073. goto fail;
  1074. }
  1075. } else {
  1076. // ignore read-only
  1077. f.m_flags |= O_WRITE;
  1078. if (!f.remove()) {
  1079. DBG_FAIL_MACRO;
  1080. goto fail;
  1081. }
  1082. }
  1083. // position to next entry if required
  1084. if (m_curPosition != (32UL*(index + 1))) {
  1085. if (!seekSet(32UL*(index + 1))) {
  1086. DBG_FAIL_MACRO;
  1087. goto fail;
  1088. }
  1089. }
  1090. }
  1091. // don't try to delete root
  1092. if (!isRoot()) {
  1093. if (!rmdir()) {
  1094. DBG_FAIL_MACRO;
  1095. goto fail;
  1096. }
  1097. }
  1098. return true;
  1099. fail:
  1100. return false;
  1101. }
  1102. //------------------------------------------------------------------------------
  1103. bool FatFile::seekSet(uint32_t pos) {
  1104. uint32_t nCur;
  1105. uint32_t nNew;
  1106. // error if file not open or seek past end of file
  1107. if (!isOpen() || pos > m_fileSize) {
  1108. DBG_FAIL_MACRO;
  1109. goto fail;
  1110. }
  1111. if (isRootFixed()) {
  1112. m_curPosition = pos;
  1113. goto done;
  1114. }
  1115. if (pos == 0) {
  1116. // set position to start of file
  1117. m_curCluster = 0;
  1118. m_curPosition = 0;
  1119. goto done;
  1120. }
  1121. // calculate cluster index for cur and new position
  1122. nCur = (m_curPosition - 1) >> (m_vol->clusterSizeShift() + 9);
  1123. nNew = (pos - 1) >> (m_vol->clusterSizeShift() + 9);
  1124. if (nNew < nCur || m_curPosition == 0) {
  1125. // must follow chain from first cluster
  1126. m_curCluster = m_firstCluster;
  1127. } else {
  1128. // advance from curPosition
  1129. nNew -= nCur;
  1130. }
  1131. while (nNew--) {
  1132. if (!m_vol->fatGet(m_curCluster, &m_curCluster)) {
  1133. DBG_FAIL_MACRO;
  1134. goto fail;
  1135. }
  1136. }
  1137. m_curPosition = pos;
  1138. done:
  1139. return true;
  1140. fail:
  1141. return false;
  1142. }
  1143. //------------------------------------------------------------------------------
  1144. // set m_fileSize for a directory
  1145. bool FatFile::setDirSize() {
  1146. uint16_t s = 0;
  1147. uint32_t cluster = m_firstCluster;
  1148. do {
  1149. if (!m_vol->fatGet(cluster, &cluster)) {
  1150. DBG_FAIL_MACRO;
  1151. goto fail;
  1152. }
  1153. s += m_vol->blocksPerCluster();
  1154. // max size if a directory file is 4096 blocks
  1155. if (s >= 4096) {
  1156. DBG_FAIL_MACRO;
  1157. goto fail;
  1158. }
  1159. } while (!m_vol->isEOC(cluster));
  1160. m_fileSize = 512L*s;
  1161. return true;
  1162. fail:
  1163. return false;
  1164. }
  1165. //------------------------------------------------------------------------------
  1166. void FatFile::setpos(FatPos_t* pos) {
  1167. m_curPosition = pos->position;
  1168. m_curCluster = pos->cluster;
  1169. }
  1170. //------------------------------------------------------------------------------
  1171. bool FatFile::sync() {
  1172. // only allow open files and directories
  1173. if (!isOpen()) {
  1174. DBG_FAIL_MACRO;
  1175. goto fail;
  1176. }
  1177. if (m_flags & F_FILE_DIR_DIRTY) {
  1178. dir_t* dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  1179. // check for deleted by another open file object
  1180. if (!dir || dir->name[0] == DIR_NAME_DELETED) {
  1181. DBG_FAIL_MACRO;
  1182. goto fail;
  1183. }
  1184. // do not set filesize for dir files
  1185. if (!isDir()) dir->fileSize = m_fileSize;
  1186. // update first cluster fields
  1187. dir->firstClusterLow = m_firstCluster & 0XFFFF;
  1188. dir->firstClusterHigh = m_firstCluster >> 16;
  1189. // set modify time if user supplied a callback date/time function
  1190. if (m_dateTime) {
  1191. m_dateTime(&dir->lastWriteDate, &dir->lastWriteTime);
  1192. dir->lastAccessDate = dir->lastWriteDate;
  1193. }
  1194. // clear directory dirty
  1195. m_flags &= ~F_FILE_DIR_DIRTY;
  1196. }
  1197. return m_vol->cacheSync();
  1198. fail:
  1199. m_writeError = true;
  1200. return false;
  1201. }
  1202. //------------------------------------------------------------------------------
  1203. bool FatFile::timestamp(FatFile* file) {
  1204. dir_t* dir;
  1205. dir_t srcDir;
  1206. // get timestamps
  1207. if (!file->dirEntry(&srcDir)) {
  1208. DBG_FAIL_MACRO;
  1209. goto fail;
  1210. }
  1211. // update directory fields
  1212. if (!sync()) {
  1213. DBG_FAIL_MACRO;
  1214. goto fail;
  1215. }
  1216. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  1217. if (!dir) {
  1218. DBG_FAIL_MACRO;
  1219. goto fail;
  1220. }
  1221. // copy timestamps
  1222. dir->lastAccessDate = srcDir.lastAccessDate;
  1223. dir->creationDate = srcDir.creationDate;
  1224. dir->creationTime = srcDir.creationTime;
  1225. dir->creationTimeTenths = srcDir.creationTimeTenths;
  1226. dir->lastWriteDate = srcDir.lastWriteDate;
  1227. dir->lastWriteTime = srcDir.lastWriteTime;
  1228. // write back entry
  1229. return m_vol->cacheSync();
  1230. fail:
  1231. return false;
  1232. }
  1233. //------------------------------------------------------------------------------
  1234. bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
  1235. uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
  1236. uint16_t dirDate;
  1237. uint16_t dirTime;
  1238. dir_t* dir;
  1239. if (!isOpen()
  1240. || year < 1980
  1241. || year > 2107
  1242. || month < 1
  1243. || month > 12
  1244. || day < 1
  1245. || day > 31
  1246. || hour > 23
  1247. || minute > 59
  1248. || second > 59) {
  1249. DBG_FAIL_MACRO;
  1250. goto fail;
  1251. }
  1252. // update directory entry
  1253. if (!sync()) {
  1254. DBG_FAIL_MACRO;
  1255. goto fail;
  1256. }
  1257. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  1258. if (!dir) {
  1259. DBG_FAIL_MACRO;
  1260. goto fail;
  1261. }
  1262. dirDate = FAT_DATE(year, month, day);
  1263. dirTime = FAT_TIME(hour, minute, second);
  1264. if (flags & T_ACCESS) {
  1265. dir->lastAccessDate = dirDate;
  1266. }
  1267. if (flags & T_CREATE) {
  1268. dir->creationDate = dirDate;
  1269. dir->creationTime = dirTime;
  1270. // seems to be units of 1/100 second not 1/10 as Microsoft states
  1271. dir->creationTimeTenths = second & 1 ? 100 : 0;
  1272. }
  1273. if (flags & T_WRITE) {
  1274. dir->lastWriteDate = dirDate;
  1275. dir->lastWriteTime = dirTime;
  1276. }
  1277. return m_vol->cacheSync();
  1278. fail:
  1279. return false;
  1280. }
  1281. //------------------------------------------------------------------------------
  1282. bool FatFile::truncate(uint32_t length) {
  1283. uint32_t newPos;
  1284. // error if not a normal file or read-only
  1285. if (!isFile() || !(m_flags & O_WRITE)) {
  1286. DBG_FAIL_MACRO;
  1287. goto fail;
  1288. }
  1289. // error if length is greater than current size
  1290. if (length > m_fileSize) {
  1291. DBG_FAIL_MACRO;
  1292. goto fail;
  1293. }
  1294. // fileSize and length are zero - nothing to do
  1295. if (m_fileSize == 0) return true;
  1296. // remember position for seek after truncation
  1297. newPos = m_curPosition > length ? length : m_curPosition;
  1298. // position to last cluster in truncated file
  1299. if (!seekSet(length)) {
  1300. DBG_FAIL_MACRO;
  1301. goto fail;
  1302. }
  1303. if (length == 0) {
  1304. // free all clusters
  1305. if (!m_vol->freeChain(m_firstCluster)) {
  1306. DBG_FAIL_MACRO;
  1307. goto fail;
  1308. }
  1309. m_firstCluster = 0;
  1310. } else {
  1311. uint32_t toFree;
  1312. if (!m_vol->fatGet(m_curCluster, &toFree)) {
  1313. DBG_FAIL_MACRO;
  1314. goto fail;
  1315. }
  1316. if (!m_vol->isEOC(toFree)) {
  1317. // free extra clusters
  1318. if (!m_vol->freeChain(toFree)) {
  1319. DBG_FAIL_MACRO;
  1320. goto fail;
  1321. }
  1322. // current cluster is end of chain
  1323. if (!m_vol->fatPutEOC(m_curCluster)) {
  1324. DBG_FAIL_MACRO;
  1325. goto fail;
  1326. }
  1327. }
  1328. }
  1329. m_fileSize = length;
  1330. // need to update directory entry
  1331. m_flags |= F_FILE_DIR_DIRTY;
  1332. if (!sync()) {
  1333. DBG_FAIL_MACRO;
  1334. goto fail;
  1335. }
  1336. // set file to correct position
  1337. return seekSet(newPos);
  1338. fail:
  1339. return false;
  1340. }
  1341. //------------------------------------------------------------------------------
  1342. int FatFile::write(const void* buf, size_t nbyte) {
  1343. // convert void* to uint8_t* - must be before goto statements
  1344. const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
  1345. cache_t* pc;
  1346. uint8_t cacheOption;
  1347. // number of bytes left to write - must be before goto statements
  1348. size_t nToWrite = nbyte;
  1349. size_t n;
  1350. // error if not a normal file or is read-only
  1351. if (!isFile() || !(m_flags & O_WRITE)) {
  1352. DBG_FAIL_MACRO;
  1353. goto fail;
  1354. }
  1355. // seek to end of file if append flag
  1356. if ((m_flags & O_APPEND)) {
  1357. if (!seekEnd()) {
  1358. DBG_FAIL_MACRO;
  1359. goto fail;
  1360. }
  1361. }
  1362. // Don't exceed max fileSize.
  1363. if (nbyte > (0XFFFFFFFF - m_curPosition)) {
  1364. DBG_FAIL_MACRO;
  1365. goto fail;
  1366. }
  1367. while (nToWrite) {
  1368. uint8_t blockOfCluster = m_vol->blockOfCluster(m_curPosition);
  1369. uint16_t blockOffset = m_curPosition & 0X1FF;
  1370. if (blockOfCluster == 0 && blockOffset == 0) {
  1371. // start of new cluster
  1372. if (m_curCluster != 0) {
  1373. uint32_t next;
  1374. if (!m_vol->fatGet(m_curCluster, &next)) {
  1375. DBG_FAIL_MACRO;
  1376. goto fail;
  1377. }
  1378. if (m_vol->isEOC(next)) {
  1379. // add cluster if at end of chain
  1380. if (!addCluster()) {
  1381. DBG_FAIL_MACRO;
  1382. goto fail;
  1383. }
  1384. } else {
  1385. m_curCluster = next;
  1386. }
  1387. } else {
  1388. if (m_firstCluster == 0) {
  1389. // allocate first cluster of file
  1390. if (!addCluster()) {
  1391. DBG_FAIL_MACRO;
  1392. goto fail;
  1393. }
  1394. m_firstCluster = m_curCluster;
  1395. } else {
  1396. m_curCluster = m_firstCluster;
  1397. }
  1398. }
  1399. }
  1400. // block for data write
  1401. uint32_t block = m_vol->clusterStartBlock(m_curCluster) + blockOfCluster;
  1402. if (blockOffset != 0 || nToWrite < 512) {
  1403. // partial block - must use cache
  1404. // max space in block
  1405. n = 512 - blockOffset;
  1406. // lesser of space and amount to write
  1407. if (n > nToWrite) n = nToWrite;
  1408. if (blockOffset == 0 && m_curPosition >= m_fileSize) {
  1409. // start of new block don't need to read into cache
  1410. cacheOption = FatCache::CACHE_RESERVE_FOR_WRITE;
  1411. } else {
  1412. // rewrite part of block
  1413. cacheOption = FatCache::CACHE_FOR_WRITE;
  1414. }
  1415. pc = m_vol->cacheFetchData(block, cacheOption);
  1416. if (!pc) {
  1417. DBG_FAIL_MACRO;
  1418. goto fail;
  1419. }
  1420. uint8_t* dst = pc->data + blockOffset;
  1421. memcpy(dst, src, n);
  1422. if (512 == (n + blockOffset)) {
  1423. // Force write if block is full - improves large writes.
  1424. if (!m_vol->cacheSyncData()) {
  1425. DBG_FAIL_MACRO;
  1426. goto fail;
  1427. }
  1428. }
  1429. #if USE_MULTI_BLOCK_IO
  1430. } else if (nToWrite >= 1024) {
  1431. // use multiple block write command
  1432. uint8_t maxBlocks = m_vol->blocksPerCluster() - blockOfCluster;
  1433. uint8_t nBlock = nToWrite >> 9;
  1434. if (nBlock > maxBlocks) nBlock = maxBlocks;
  1435. n = 512*nBlock;
  1436. if (m_vol->cacheBlockNumber() <= block
  1437. && block < (m_vol->cacheBlockNumber() + nBlock)) {
  1438. // invalidate cache if block is in cache
  1439. m_vol->cacheInvalidate();
  1440. }
  1441. if (!m_vol->writeBlocks(block, src, nBlock)) {
  1442. DBG_FAIL_MACRO;
  1443. goto fail;
  1444. }
  1445. #endif // USE_MULTI_BLOCK_IO
  1446. } else {
  1447. // use single block write command
  1448. n = 512;
  1449. if (m_vol->cacheBlockNumber() == block) {
  1450. m_vol->cacheInvalidate();
  1451. }
  1452. if (!m_vol->writeBlock(block, src)) {
  1453. DBG_FAIL_MACRO;
  1454. goto fail;
  1455. }
  1456. }
  1457. m_curPosition += n;
  1458. src += n;
  1459. nToWrite -= n;
  1460. }
  1461. if (m_curPosition > m_fileSize) {
  1462. // update fileSize and insure sync will update dir entry
  1463. m_fileSize = m_curPosition;
  1464. m_flags |= F_FILE_DIR_DIRTY;
  1465. } else if (m_dateTime) {
  1466. // insure sync will update modified date and time
  1467. m_flags |= F_FILE_DIR_DIRTY;
  1468. }
  1469. if (m_flags & O_SYNC) {
  1470. if (!sync()) {
  1471. DBG_FAIL_MACRO;
  1472. goto fail;
  1473. }
  1474. }
  1475. return nbyte;
  1476. fail:
  1477. // return for write error
  1478. m_writeError = true;
  1479. return -1;
  1480. }