FatFile.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491
  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, FatCache::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(FatCache::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(FatCache::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, FatCache::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, FatCache::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. // Check for cache sector in read range.
  767. if (sector <= m_vol->cacheSectorNumber()
  768. && m_vol->cacheSectorNumber() < (sector + ns)) {
  769. // Flush cache if cache sector is in the range.
  770. if (!m_vol->cacheSyncData()) {
  771. DBG_FAIL_MACRO;
  772. goto fail;
  773. }
  774. }
  775. if (!m_vol->readSectors(sector, dst, ns)) {
  776. DBG_FAIL_MACRO;
  777. goto fail;
  778. }
  779. #endif // USE_MULTI_SECTOR_IO
  780. } else {
  781. // read single sector
  782. n = m_vol->bytesPerSector();
  783. if (!m_vol->readSector(sector, dst)) {
  784. DBG_FAIL_MACRO;
  785. goto fail;
  786. }
  787. }
  788. dst += n;
  789. m_curPosition += n;
  790. toRead -= n;
  791. }
  792. return nbyte - toRead;
  793. fail:
  794. m_error |= READ_ERROR;
  795. return -1;
  796. }
  797. //------------------------------------------------------------------------------
  798. int8_t FatFile::readDir(DirFat_t* dir) {
  799. int16_t n;
  800. // if not a directory file or miss-positioned return an error
  801. if (!isDir() || (0X1F & m_curPosition)) {
  802. return -1;
  803. }
  804. while (1) {
  805. n = read(dir, sizeof(DirFat_t));
  806. if (n != sizeof(DirFat_t)) {
  807. return n == 0 ? 0 : -1;
  808. }
  809. // last entry if FAT_NAME_FREE
  810. if (dir->name[0] == FAT_NAME_FREE) {
  811. return 0;
  812. }
  813. // skip empty entries and entry for . and ..
  814. if (dir->name[0] == FAT_NAME_DELETED || dir->name[0] == '.') {
  815. continue;
  816. }
  817. // return if normal file or subdirectory
  818. if (isFileOrSubdir(dir)) {
  819. return n;
  820. }
  821. }
  822. }
  823. //------------------------------------------------------------------------------
  824. // Read next directory entry into the cache
  825. // Assumes file is correctly positioned
  826. DirFat_t* FatFile::readDirCache(bool skipReadOk) {
  827. uint8_t i = (m_curPosition >> 5) & 0XF;
  828. if (i == 0 || !skipReadOk) {
  829. int8_t n = read(&n, 1);
  830. if (n != 1) {
  831. if (n != 0) {
  832. DBG_FAIL_MACRO;
  833. }
  834. goto fail;
  835. }
  836. m_curPosition += 31;
  837. } else {
  838. m_curPosition += 32;
  839. }
  840. // return pointer to entry
  841. return reinterpret_cast<DirFat_t*>(m_vol->cacheAddress()) + i;
  842. fail:
  843. return nullptr;
  844. }
  845. //------------------------------------------------------------------------------
  846. bool FatFile::remove(const char* path) {
  847. FatFile file;
  848. if (!file.open(this, path, O_WRONLY)) {
  849. DBG_FAIL_MACRO;
  850. goto fail;
  851. }
  852. return file.remove();
  853. fail:
  854. return false;
  855. }
  856. //------------------------------------------------------------------------------
  857. bool FatFile::rename(const char* newPath) {
  858. return rename(m_vol->vwd(), newPath);
  859. }
  860. //------------------------------------------------------------------------------
  861. bool FatFile::rename(FatFile* dirFile, const char* newPath) {
  862. DirFat_t entry;
  863. uint32_t dirCluster = 0;
  864. FatFile file;
  865. FatFile oldFile;
  866. cache_t* pc;
  867. DirFat_t* dir;
  868. // Must be an open file or subdirectory.
  869. if (!(isFile() || isSubDir())) {
  870. DBG_FAIL_MACRO;
  871. goto fail;
  872. }
  873. // Can't rename LFN in 8.3 mode.
  874. if (!USE_LONG_FILE_NAMES && isLFN()) {
  875. DBG_FAIL_MACRO;
  876. goto fail;
  877. }
  878. // Can't move file to new volume.
  879. if (m_vol != dirFile->m_vol) {
  880. DBG_FAIL_MACRO;
  881. goto fail;
  882. }
  883. // sync() and cache directory entry
  884. sync();
  885. oldFile = *this;
  886. dir = cacheDirEntry(FatCache::CACHE_FOR_READ);
  887. if (!dir) {
  888. DBG_FAIL_MACRO;
  889. goto fail;
  890. }
  891. // save directory entry
  892. memcpy(&entry, dir, sizeof(entry));
  893. // make directory entry for new path
  894. if (isFile()) {
  895. if (!file.open(dirFile, newPath, O_CREAT | O_EXCL | O_WRONLY)) {
  896. DBG_FAIL_MACRO;
  897. goto fail;
  898. }
  899. } else {
  900. // don't create missing path prefix components
  901. if (!file.mkdir(dirFile, newPath, false)) {
  902. DBG_FAIL_MACRO;
  903. goto fail;
  904. }
  905. // save cluster containing new dot dot
  906. dirCluster = file.m_firstCluster;
  907. }
  908. // change to new directory entry
  909. m_dirSector = file.m_dirSector;
  910. m_dirIndex = file.m_dirIndex;
  911. m_lfnOrd = file.m_lfnOrd;
  912. m_dirCluster = file.m_dirCluster;
  913. // mark closed to avoid possible destructor close call
  914. file.m_attributes = FILE_ATTR_CLOSED;
  915. file.m_flags = 0;
  916. // cache new directory entry
  917. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  918. if (!dir) {
  919. DBG_FAIL_MACRO;
  920. goto fail;
  921. }
  922. // copy all but name and name flags to new directory entry
  923. memcpy(&dir->createTimeMs, &entry.createTimeMs,
  924. sizeof(entry) - sizeof(dir->name) - 2);
  925. dir->attributes = entry.attributes;
  926. // update dot dot if directory
  927. if (dirCluster) {
  928. // get new dot dot
  929. uint32_t sector = m_vol->clusterStartSector(dirCluster);
  930. pc = m_vol->cacheFetchData(sector, FatCache::CACHE_FOR_READ);
  931. if (!pc) {
  932. DBG_FAIL_MACRO;
  933. goto fail;
  934. }
  935. memcpy(&entry, &pc->dir[1], sizeof(entry));
  936. // free unused cluster
  937. if (!m_vol->freeChain(dirCluster)) {
  938. DBG_FAIL_MACRO;
  939. goto fail;
  940. }
  941. // store new dot dot
  942. sector = m_vol->clusterStartSector(m_firstCluster);
  943. pc = m_vol->cacheFetchData(sector, FatCache::CACHE_FOR_WRITE);
  944. if (!pc) {
  945. DBG_FAIL_MACRO;
  946. goto fail;
  947. }
  948. memcpy(&pc->dir[1], &entry, sizeof(entry));
  949. }
  950. // Remove old directory entry;
  951. oldFile.m_firstCluster = 0;
  952. oldFile.m_flags = FILE_FLAG_WRITE;
  953. oldFile.m_attributes = FILE_ATTR_FILE;
  954. if (!oldFile.remove()) {
  955. DBG_FAIL_MACRO;
  956. goto fail;
  957. }
  958. return m_vol->cacheSync();
  959. fail:
  960. return false;
  961. }
  962. //------------------------------------------------------------------------------
  963. bool FatFile::rmdir() {
  964. // must be open subdirectory
  965. if (!isSubDir() || (!USE_LONG_FILE_NAMES && isLFN())) {
  966. DBG_FAIL_MACRO;
  967. goto fail;
  968. }
  969. rewind();
  970. // make sure directory is empty
  971. while (1) {
  972. DirFat_t* dir = readDirCache(true);
  973. if (!dir) {
  974. // EOF if no error.
  975. if (!getError()) {
  976. break;
  977. }
  978. DBG_FAIL_MACRO;
  979. goto fail;
  980. }
  981. // done if past last used entry
  982. if (dir->name[0] == FAT_NAME_FREE) {
  983. break;
  984. }
  985. // skip empty slot, '.' or '..'
  986. if (dir->name[0] == FAT_NAME_DELETED || dir->name[0] == '.') {
  987. continue;
  988. }
  989. // error not empty
  990. if (isFileOrSubdir(dir)) {
  991. DBG_FAIL_MACRO;
  992. goto fail;
  993. }
  994. }
  995. // convert empty directory to normal file for remove
  996. m_attributes = FILE_ATTR_FILE;
  997. m_flags |= FILE_FLAG_WRITE;
  998. return remove();
  999. fail:
  1000. return false;
  1001. }
  1002. //------------------------------------------------------------------------------
  1003. bool FatFile::rmRfStar() {
  1004. uint16_t index;
  1005. FatFile f;
  1006. if (!isDir()) {
  1007. DBG_FAIL_MACRO;
  1008. goto fail;
  1009. }
  1010. rewind();
  1011. while (1) {
  1012. // remember position
  1013. index = m_curPosition/32;
  1014. DirFat_t* dir = readDirCache();
  1015. if (!dir) {
  1016. // At EOF if no error.
  1017. if (!getError()) {
  1018. break;
  1019. }
  1020. DBG_FAIL_MACRO;
  1021. goto fail;
  1022. }
  1023. // done if past last entry
  1024. if (dir->name[0] == FAT_NAME_FREE) {
  1025. break;
  1026. }
  1027. // skip empty slot or '.' or '..'
  1028. if (dir->name[0] == FAT_NAME_DELETED || dir->name[0] == '.') {
  1029. continue;
  1030. }
  1031. // skip if part of long file name or volume label in root
  1032. if (!isFileOrSubdir(dir)) {
  1033. continue;
  1034. }
  1035. if (!f.open(this, index, O_RDONLY)) {
  1036. DBG_FAIL_MACRO;
  1037. goto fail;
  1038. }
  1039. if (f.isSubDir()) {
  1040. // recursively delete
  1041. if (!f.rmRfStar()) {
  1042. DBG_FAIL_MACRO;
  1043. goto fail;
  1044. }
  1045. } else {
  1046. // ignore read-only
  1047. f.m_flags |= FILE_FLAG_WRITE;
  1048. if (!f.remove()) {
  1049. DBG_FAIL_MACRO;
  1050. goto fail;
  1051. }
  1052. }
  1053. // position to next entry if required
  1054. if (m_curPosition != (32UL*(index + 1))) {
  1055. if (!seekSet(32UL*(index + 1))) {
  1056. DBG_FAIL_MACRO;
  1057. goto fail;
  1058. }
  1059. }
  1060. }
  1061. // don't try to delete root
  1062. if (!isRoot()) {
  1063. if (!rmdir()) {
  1064. DBG_FAIL_MACRO;
  1065. goto fail;
  1066. }
  1067. }
  1068. return true;
  1069. fail:
  1070. return false;
  1071. }
  1072. //------------------------------------------------------------------------------
  1073. bool FatFile::seekSet(uint32_t pos) {
  1074. uint32_t nCur;
  1075. uint32_t nNew;
  1076. uint32_t tmp = m_curCluster;
  1077. // error if file not open
  1078. if (!isOpen()) {
  1079. DBG_FAIL_MACRO;
  1080. goto fail;
  1081. }
  1082. // Optimize O_APPEND writes.
  1083. if (pos == m_curPosition) {
  1084. return true;
  1085. }
  1086. if (pos == 0) {
  1087. // set position to start of file
  1088. m_curCluster = 0;
  1089. goto done;
  1090. }
  1091. if (isFile()) {
  1092. if (pos > m_fileSize) {
  1093. DBG_FAIL_MACRO;
  1094. goto fail;
  1095. }
  1096. } else if (isRootFixed()) {
  1097. if (pos <= 32*m_vol->rootDirEntryCount()) {
  1098. goto done;
  1099. }
  1100. DBG_FAIL_MACRO;
  1101. goto fail;
  1102. }
  1103. // calculate cluster index for new position
  1104. nNew = (pos - 1) >> (m_vol->bytesPerClusterShift());
  1105. #if USE_FAT_FILE_FLAG_CONTIGUOUS
  1106. if (isContiguous()) {
  1107. m_curCluster = m_firstCluster + nNew;
  1108. goto done;
  1109. }
  1110. #endif // USE_FAT_FILE_FLAG_CONTIGUOUS
  1111. // calculate cluster index for current position
  1112. nCur = (m_curPosition - 1) >> (m_vol->bytesPerClusterShift());
  1113. if (nNew < nCur || m_curPosition == 0) {
  1114. // must follow chain from first cluster
  1115. m_curCluster = isRoot32() ? m_vol->rootDirStart() : m_firstCluster;
  1116. } else {
  1117. // advance from curPosition
  1118. nNew -= nCur;
  1119. }
  1120. while (nNew--) {
  1121. if (m_vol->fatGet(m_curCluster, &m_curCluster) <= 0) {
  1122. DBG_FAIL_MACRO;
  1123. goto fail;
  1124. }
  1125. }
  1126. done:
  1127. m_curPosition = pos;
  1128. m_flags &= ~FILE_FLAG_PREALLOCATE;
  1129. return true;
  1130. fail:
  1131. m_curCluster = tmp;
  1132. return false;
  1133. }
  1134. //------------------------------------------------------------------------------
  1135. bool FatFile::sync() {
  1136. uint16_t date, time;
  1137. uint8_t ms10;
  1138. if (!isOpen()) {
  1139. return true;
  1140. }
  1141. if (m_flags & FILE_FLAG_DIR_DIRTY) {
  1142. DirFat_t* dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  1143. // check for deleted by another open file object
  1144. if (!dir || dir->name[0] == FAT_NAME_DELETED) {
  1145. DBG_FAIL_MACRO;
  1146. goto fail;
  1147. }
  1148. // do not set filesize for dir files
  1149. if (isFile()) {
  1150. setLe32(dir->fileSize, m_fileSize);
  1151. }
  1152. // update first cluster fields
  1153. setLe16(dir->firstClusterLow, m_firstCluster & 0XFFFF);
  1154. setLe16(dir->firstClusterHigh, m_firstCluster >> 16);
  1155. // set modify time if user supplied a callback date/time function
  1156. if (FsDateTime::callback) {
  1157. FsDateTime::callback(&date, &time, &ms10);
  1158. setLe16(dir->modifyDate, date);
  1159. setLe16(dir->accessDate, date);
  1160. setLe16(dir->modifyTime, time);
  1161. }
  1162. // clear directory dirty
  1163. m_flags &= ~FILE_FLAG_DIR_DIRTY;
  1164. }
  1165. if (m_vol->cacheSync()) {
  1166. return true;
  1167. }
  1168. DBG_FAIL_MACRO;
  1169. fail:
  1170. m_error |= WRITE_ERROR;
  1171. return false;
  1172. }
  1173. //------------------------------------------------------------------------------
  1174. bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
  1175. uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
  1176. uint16_t dirDate;
  1177. uint16_t dirTime;
  1178. DirFat_t* dir;
  1179. if (!isFile()
  1180. || year < 1980
  1181. || year > 2107
  1182. || month < 1
  1183. || month > 12
  1184. || day < 1
  1185. || day > 31
  1186. || hour > 23
  1187. || minute > 59
  1188. || second > 59) {
  1189. DBG_FAIL_MACRO;
  1190. goto fail;
  1191. }
  1192. // update directory entry
  1193. if (!sync()) {
  1194. DBG_FAIL_MACRO;
  1195. goto fail;
  1196. }
  1197. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  1198. if (!dir) {
  1199. DBG_FAIL_MACRO;
  1200. goto fail;
  1201. }
  1202. dirDate = FS_DATE(year, month, day);
  1203. dirTime = FS_TIME(hour, minute, second);
  1204. if (flags & T_ACCESS) {
  1205. setLe16(dir->accessDate, dirDate);
  1206. }
  1207. if (flags & T_CREATE) {
  1208. setLe16(dir->createDate, dirDate);
  1209. setLe16(dir->createTime, dirTime);
  1210. // units of 10 ms
  1211. dir->createTimeMs = second & 1 ? 100 : 0;
  1212. }
  1213. if (flags & T_WRITE) {
  1214. setLe16(dir->modifyDate, dirDate);
  1215. setLe16(dir->modifyTime, dirTime);
  1216. }
  1217. return m_vol->cacheSync();
  1218. fail:
  1219. return false;
  1220. }
  1221. //------------------------------------------------------------------------------
  1222. bool FatFile::truncate() {
  1223. uint32_t toFree;
  1224. // error if not a normal file or read-only
  1225. if (!isWritable()) {
  1226. DBG_FAIL_MACRO;
  1227. goto fail;
  1228. }
  1229. if (m_firstCluster == 0) {
  1230. return true;
  1231. }
  1232. if (m_curCluster) {
  1233. toFree = 0;
  1234. int8_t fg = m_vol->fatGet(m_curCluster, &toFree);
  1235. if (fg < 0) {
  1236. DBG_FAIL_MACRO;
  1237. goto fail;
  1238. }
  1239. if (fg) {
  1240. // current cluster is end of chain
  1241. if (!m_vol->fatPutEOC(m_curCluster)) {
  1242. DBG_FAIL_MACRO;
  1243. goto fail;
  1244. }
  1245. }
  1246. } else {
  1247. toFree = m_firstCluster;
  1248. m_firstCluster = 0;
  1249. }
  1250. if (toFree) {
  1251. if (!m_vol->freeChain(toFree)) {
  1252. DBG_FAIL_MACRO;
  1253. goto fail;
  1254. }
  1255. }
  1256. m_fileSize = m_curPosition;
  1257. // need to update directory entry
  1258. m_flags |= FILE_FLAG_DIR_DIRTY;
  1259. if (!sync()) {
  1260. DBG_FAIL_MACRO;
  1261. goto fail;
  1262. }
  1263. return true;
  1264. fail:
  1265. return false;
  1266. }
  1267. //------------------------------------------------------------------------------
  1268. size_t FatFile::write(const void* buf, size_t nbyte) {
  1269. // convert void* to uint8_t* - must be before goto statements
  1270. const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
  1271. cache_t* pc;
  1272. uint8_t cacheOption;
  1273. // number of bytes left to write - must be before goto statements
  1274. size_t nToWrite = nbyte;
  1275. size_t n;
  1276. // error if not a normal file or is read-only
  1277. if (!isWritable()) {
  1278. DBG_FAIL_MACRO;
  1279. goto fail;
  1280. }
  1281. // seek to end of file if append flag
  1282. if ((m_flags & FILE_FLAG_APPEND)) {
  1283. if (!seekSet(m_fileSize)) {
  1284. DBG_FAIL_MACRO;
  1285. goto fail;
  1286. }
  1287. }
  1288. // Don't exceed max fileSize.
  1289. if (nbyte > (0XFFFFFFFF - m_curPosition)) {
  1290. DBG_FAIL_MACRO;
  1291. goto fail;
  1292. }
  1293. while (nToWrite) {
  1294. uint8_t sectorOfCluster = m_vol->sectorOfCluster(m_curPosition);
  1295. uint16_t sectorOffset = m_curPosition & m_vol->sectorMask();
  1296. if (sectorOfCluster == 0 && sectorOffset == 0) {
  1297. // start of new cluster
  1298. if (m_curCluster != 0) {
  1299. #if USE_FAT_FILE_FLAG_CONTIGUOUS
  1300. int8_t fg;
  1301. if (isContiguous() && m_fileSize > m_curPosition) {
  1302. m_curCluster++;
  1303. fg = 1;
  1304. } else {
  1305. fg = m_vol->fatGet(m_curCluster, &m_curCluster);
  1306. if (fg < 0) {
  1307. DBG_FAIL_MACRO;
  1308. goto fail;
  1309. }
  1310. }
  1311. #else // USE_FAT_FILE_FLAG_CONTIGUOUS
  1312. int8_t fg = m_vol->fatGet(m_curCluster, &m_curCluster);
  1313. if (fg < 0) {
  1314. DBG_FAIL_MACRO;
  1315. goto fail;
  1316. }
  1317. #endif // USE_FAT_FILE_FLAG_CONTIGUOUS
  1318. if (fg == 0) {
  1319. // add cluster if at end of chain
  1320. if (!addCluster()) {
  1321. DBG_FAIL_MACRO;
  1322. goto fail;
  1323. }
  1324. }
  1325. } else {
  1326. if (m_firstCluster == 0) {
  1327. // allocate first cluster of file
  1328. if (!addCluster()) {
  1329. DBG_FAIL_MACRO;
  1330. goto fail;
  1331. }
  1332. m_firstCluster = m_curCluster;
  1333. } else {
  1334. m_curCluster = m_firstCluster;
  1335. }
  1336. }
  1337. }
  1338. // sector for data write
  1339. uint32_t sector = m_vol->clusterStartSector(m_curCluster)
  1340. + sectorOfCluster;
  1341. if (sectorOffset != 0 || nToWrite < m_vol->bytesPerSector()) {
  1342. // partial sector - must use cache
  1343. // max space in sector
  1344. n = m_vol->bytesPerSector() - sectorOffset;
  1345. // lesser of space and amount to write
  1346. if (n > nToWrite) {
  1347. n = nToWrite;
  1348. }
  1349. if (sectorOffset == 0 &&
  1350. (m_curPosition >= m_fileSize || m_flags & FILE_FLAG_PREALLOCATE)) {
  1351. // start of new sector don't need to read into cache
  1352. cacheOption = FatCache::CACHE_RESERVE_FOR_WRITE;
  1353. } else {
  1354. // rewrite part of sector
  1355. cacheOption = FatCache::CACHE_FOR_WRITE;
  1356. }
  1357. pc = m_vol->cacheFetchData(sector, cacheOption);
  1358. if (!pc) {
  1359. DBG_FAIL_MACRO;
  1360. goto fail;
  1361. }
  1362. uint8_t* dst = pc->data + sectorOffset;
  1363. memcpy(dst, src, n);
  1364. if (m_vol->bytesPerSector() == (n + sectorOffset)) {
  1365. // Force write if sector is full - improves large writes.
  1366. if (!m_vol->cacheSyncData()) {
  1367. DBG_FAIL_MACRO;
  1368. goto fail;
  1369. }
  1370. }
  1371. #if USE_MULTI_SECTOR_IO
  1372. } else if (nToWrite >= 2*m_vol->bytesPerSector()) {
  1373. // use multiple sector write command
  1374. uint32_t maxSectors = m_vol->sectorsPerCluster() - sectorOfCluster;
  1375. uint32_t nSector = nToWrite >> m_vol->bytesPerSectorShift();
  1376. if (nSector > maxSectors) {
  1377. nSector = maxSectors;
  1378. }
  1379. n = nSector << m_vol->bytesPerSectorShift();
  1380. // Check for cache sector in write range.
  1381. if (sector <= m_vol->cacheSectorNumber()
  1382. && m_vol->cacheSectorNumber() < (sector + nSector)) {
  1383. // Invalidate cache if cache sector is in the range.
  1384. m_vol->cacheInvalidate();
  1385. }
  1386. if (!m_vol->writeSectors(sector, src, nSector)) {
  1387. DBG_FAIL_MACRO;
  1388. goto fail;
  1389. }
  1390. #endif // USE_MULTI_SECTOR_IO
  1391. } else {
  1392. // use single sector write command
  1393. n = m_vol->bytesPerSector();
  1394. if (m_vol->cacheSectorNumber() == sector) {
  1395. m_vol->cacheInvalidate();
  1396. }
  1397. if (!m_vol->writeSector(sector, src)) {
  1398. DBG_FAIL_MACRO;
  1399. goto fail;
  1400. }
  1401. }
  1402. m_curPosition += n;
  1403. src += n;
  1404. nToWrite -= n;
  1405. }
  1406. if (m_curPosition > m_fileSize) {
  1407. // update fileSize and insure sync will update dir entry
  1408. m_fileSize = m_curPosition;
  1409. m_flags |= FILE_FLAG_DIR_DIRTY;
  1410. } else if (FsDateTime::callback) {
  1411. // insure sync will update modified date and time
  1412. m_flags |= FILE_FLAG_DIR_DIRTY;
  1413. }
  1414. return nbyte;
  1415. fail:
  1416. // return for write error
  1417. m_error |= WRITE_ERROR;
  1418. return -1;
  1419. }