Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

1495 Zeilen
36KB

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