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