FatFile.cpp 37 KB

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