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

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