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.

684 lines
17KB

  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. //------------------------------------------------------------------------------
  22. //
  23. uint8_t FatFile::lfnChecksum(uint8_t* name) {
  24. uint8_t sum = 0;
  25. for (uint8_t i = 0; i < 11; i++) {
  26. sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + name[i];
  27. }
  28. return sum;
  29. }
  30. #if USE_LONG_FILE_NAMES
  31. //------------------------------------------------------------------------------
  32. // Saves about 90 bytes of flash on 328 over tolower().
  33. inline char lfnToLower(char c) {
  34. return 'A' <= c && c <= 'Z' ? c + 'a' - 'A' : c;
  35. }
  36. //------------------------------------------------------------------------------
  37. // Daniel Bernstein University of Illinois at Chicago.
  38. // Original had + instead of ^
  39. static uint16_t Bernstein(uint16_t hash, const char *str, size_t len) {
  40. for (size_t i = 0; i < len; i++) {
  41. // hash = hash * 33 ^ str[i];
  42. hash = ((hash << 5) + hash) ^ str[i];
  43. }
  44. return hash;
  45. }
  46. //------------------------------------------------------------------------------
  47. /**
  48. * Fetch a 16-bit long file name character.
  49. *
  50. * \param[in] ldir Pointer to long file name directory entry.
  51. * \param[in] i Index of character.
  52. * \return The 16-bit character.
  53. */
  54. static uint16_t lfnGetChar(ldir_t *ldir, uint8_t i) {
  55. if (i < LDIR_NAME1_DIM) {
  56. return ldir->name1[i];
  57. } else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM)) {
  58. return ldir->name2[i - LDIR_NAME1_DIM];
  59. } else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM + LDIR_NAME2_DIM)) {
  60. return ldir->name3[i - LDIR_NAME1_DIM - LDIR_NAME2_DIM];
  61. }
  62. return 0;
  63. }
  64. //------------------------------------------------------------------------------
  65. static bool lfnGetName(ldir_t *ldir, char* name, size_t n) {
  66. uint8_t i;
  67. size_t k = 13*((ldir->ord & 0X1F) - 1);
  68. for (i = 0; i < 13; i++) {
  69. uint16_t c = lfnGetChar(ldir, i);
  70. if (c == 0 || k >= n) {
  71. break;
  72. }
  73. name[k++] = c >= 0X7F ? '?' : c;
  74. }
  75. // Terminate with zero byte if name fits.
  76. if (k < n && (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY)) {
  77. name[k] = 0;
  78. }
  79. // Truncate if name is too long.
  80. name[n - 1] = 0;
  81. return true;
  82. }
  83. //------------------------------------------------------------------------------
  84. inline bool lfnLegalChar(char c) {
  85. if (c == '/' || c == '\\' || c == '"' || c == '*' ||
  86. c == ':' || c == '<' || c == '>' || c == '?' || c == '|') {
  87. return false;
  88. }
  89. return 0X1F < c && c < 0X7F;
  90. }
  91. //------------------------------------------------------------------------------
  92. /**
  93. * Store a 16-bit long file name character.
  94. *
  95. * \param[in] ldir Pointer to long file name directory entry.
  96. * \param[in] i Index of character.
  97. * \param[in] c The 16-bit character.
  98. */
  99. static void lfnPutChar(ldir_t *ldir, uint8_t i, uint16_t c) {
  100. if (i < LDIR_NAME1_DIM) {
  101. ldir->name1[i] = c;
  102. } else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM)) {
  103. ldir->name2[i - LDIR_NAME1_DIM] = c;
  104. } else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM + LDIR_NAME2_DIM)) {
  105. ldir->name3[i - LDIR_NAME1_DIM - LDIR_NAME2_DIM] = c;
  106. }
  107. }
  108. //------------------------------------------------------------------------------
  109. static void lfnPutName(ldir_t *ldir, const char* name, size_t n) {
  110. size_t k = 13*((ldir->ord & 0X1F) - 1);
  111. for (uint8_t i = 0; i < 13; i++, k++) {
  112. uint16_t c = k < n ? name[k] : k == n ? 0 : 0XFFFF;
  113. lfnPutChar(ldir, i, c);
  114. }
  115. }
  116. //==============================================================================
  117. bool FatFile::getName(char* name, size_t size) {
  118. FatFile dirFile;
  119. ldir_t* ldir;
  120. if (!isOpen() || size < 13) {
  121. DBG_FAIL_MACRO;
  122. goto fail;
  123. }
  124. if (!isLFN()) {
  125. return getSFN(name);
  126. }
  127. if (!dirFile.openCluster(this)) {
  128. DBG_FAIL_MACRO;
  129. goto fail;
  130. }
  131. for (uint8_t ord = 1; ord <= m_lfnOrd; ord++) {
  132. if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
  133. DBG_FAIL_MACRO;
  134. goto fail;
  135. }
  136. ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
  137. if (!ldir) {
  138. DBG_FAIL_MACRO;
  139. goto fail;
  140. }
  141. if (ldir->attr != DIR_ATT_LONG_NAME) {
  142. DBG_FAIL_MACRO;
  143. goto fail;
  144. }
  145. if (ord != (ldir->ord & 0X1F)) {
  146. DBG_FAIL_MACRO;
  147. goto fail;
  148. }
  149. if (!lfnGetName(ldir, name, size)) {
  150. DBG_FAIL_MACRO;
  151. goto fail;
  152. }
  153. if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
  154. return true;
  155. }
  156. }
  157. // Fall into fail.
  158. DBG_FAIL_MACRO;
  159. fail:
  160. name[0] = 0;
  161. return false;
  162. }
  163. //------------------------------------------------------------------------------
  164. bool FatFile::openCluster(FatFile* file) {
  165. if (file->m_dirCluster == 0) {
  166. return openRoot(file->m_vol);
  167. }
  168. memset(this, 0, sizeof(FatFile));
  169. m_attr = FILE_ATTR_SUBDIR;
  170. m_flags = O_READ;
  171. m_vol = file->m_vol;
  172. m_firstCluster = file->m_dirCluster;
  173. return true;
  174. }
  175. //------------------------------------------------------------------------------
  176. bool FatFile::parsePathName(const char* path,
  177. fname_t* fname, const char** ptr) {
  178. char c;
  179. bool is83;
  180. uint8_t bit = DIR_NT_LC_BASE;
  181. uint8_t lc = 0;
  182. uint8_t uc = 0;
  183. uint8_t i = 0;
  184. uint8_t in = 7;
  185. int end;
  186. int len = 0;
  187. int si;
  188. int dot;
  189. // Skip leading spaces.
  190. while (*path == ' ') {
  191. path++;
  192. }
  193. fname->lfn = path;
  194. for (len = 0; ; len++) {
  195. c = path[len];
  196. if (c == 0 || isDirSeparator(c)) {
  197. break;
  198. }
  199. if (!lfnLegalChar(c)) {
  200. return false;
  201. }
  202. }
  203. // Advance to next path component.
  204. for (end = len; path[end] == ' ' || isDirSeparator(path[end]); end++) {}
  205. *ptr = &path[end];
  206. // Back over spaces and dots.
  207. while (len) {
  208. c = path[len - 1];
  209. if (c != '.' && c != ' ') {
  210. break;
  211. }
  212. len--;
  213. }
  214. // Max length of LFN is 255.
  215. if (len > 255) {
  216. return false;
  217. }
  218. fname->len = len;
  219. // Blank file short name.
  220. for (uint8_t k = 0; k < 11; k++) {
  221. fname->sfn[k] = ' ';
  222. }
  223. // skip leading spaces and dots.
  224. for (si = 0; path[si] == '.' || path[si] == ' '; si++) {}
  225. // Not 8.3 if leading dot or space.
  226. is83 = !si;
  227. // find last dot.
  228. for (dot = len - 1; dot >= 0 && path[dot] != '.'; dot--) {}
  229. for (; si < len; si++) {
  230. c = path[si];
  231. if (c == ' ' || (c == '.' && dot != si)) {
  232. is83 = false;
  233. continue;
  234. }
  235. if (!legal83Char(c) && si != dot) {
  236. is83 = false;
  237. c = '_';
  238. }
  239. if (si == dot || i > in) {
  240. if (in == 10) {
  241. // Done - extension longer than three characters.
  242. is83 = false;
  243. break;
  244. }
  245. if (si != dot) {
  246. is83 = false;
  247. }
  248. // Break if no dot and base-name is longer than eight characters.
  249. if (si > dot) {
  250. break;
  251. }
  252. si = dot;
  253. in = 10; // Max index for full 8.3 name.
  254. i = 8; // Place for extension.
  255. bit = DIR_NT_LC_EXT; // bit for extension.
  256. } else {
  257. if ('a' <= c && c <= 'z') {
  258. c += 'A' - 'a';
  259. lc |= bit;
  260. } else if ('A' <= c && c <= 'Z') {
  261. uc |= bit;
  262. }
  263. fname->sfn[i++] = c;
  264. if (i < 7) {
  265. fname->seqPos = i;
  266. }
  267. }
  268. }
  269. if (fname->sfn[0] == ' ') {
  270. return false;
  271. }
  272. if (is83) {
  273. fname->flags = lc & uc ? FNAME_FLAG_MIXED_CASE : lc;
  274. } else {
  275. fname->flags = FNAME_FLAG_LOST_CHARS;
  276. fname->sfn[fname->seqPos] = '~';
  277. fname->sfn[fname->seqPos + 1] = '1';
  278. }
  279. return true;
  280. }
  281. //------------------------------------------------------------------------------
  282. bool FatFile::open(FatFile* dirFile, fname_t* fname, uint8_t oflag) {
  283. bool fnameFound = false;
  284. uint8_t lfnOrd = 0;
  285. uint8_t freeNeed;
  286. uint8_t freeFound = 0;
  287. uint8_t ord = 0;
  288. uint8_t chksum = 0;
  289. uint16_t freeIndex = 0;
  290. uint16_t curIndex;
  291. dir_t* dir;
  292. ldir_t* ldir;
  293. size_t len = fname->len;
  294. if (!dirFile->isDir() || isOpen()) {
  295. DBG_FAIL_MACRO;
  296. goto fail;
  297. }
  298. // Number of directory entries needed.
  299. freeNeed = fname->flags & FNAME_FLAG_NEED_LFN ? 1 + (len + 12)/13 : 1;
  300. dirFile->rewind();
  301. while (1) {
  302. curIndex = dirFile->m_curPosition/32;
  303. dir = dirFile->readDirCache(true);
  304. if (!dir) {
  305. if (dirFile->getError()) {
  306. DBG_FAIL_MACRO;
  307. goto fail;
  308. }
  309. // At EOF
  310. goto create;
  311. }
  312. if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == DIR_NAME_FREE) {
  313. if (freeFound == 0) {
  314. freeIndex = curIndex;
  315. }
  316. if (freeFound < freeNeed) {
  317. freeFound++;
  318. }
  319. if (dir->name[0] == DIR_NAME_FREE) {
  320. goto create;
  321. }
  322. } else {
  323. if (freeFound < freeNeed) {
  324. freeFound = 0;
  325. }
  326. }
  327. // skip empty slot or '.' or '..'
  328. if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
  329. lfnOrd = 0;
  330. } else if (DIR_IS_LONG_NAME(dir)) {
  331. ldir_t *ldir = reinterpret_cast<ldir_t*>(dir);
  332. if (!lfnOrd) {
  333. if ((ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) == 0) {
  334. continue;
  335. }
  336. lfnOrd = ord = ldir->ord & 0X1F;
  337. chksum = ldir->chksum;
  338. } else if (ldir->ord != --ord || chksum != ldir->chksum) {
  339. lfnOrd = 0;
  340. continue;
  341. }
  342. size_t k = 13*(ord - 1);
  343. if (k >= len) {
  344. // Not found.
  345. lfnOrd = 0;
  346. continue;
  347. }
  348. for (uint8_t i = 0; i < 13; i++) {
  349. uint16_t u = lfnGetChar(ldir, i);
  350. if (k == len) {
  351. if (u != 0) {
  352. // Not found.
  353. lfnOrd = 0;
  354. }
  355. break;
  356. }
  357. if (u > 255 || lfnToLower(u) != lfnToLower(fname->lfn[k++])) {
  358. // Not found.
  359. lfnOrd = 0;
  360. break;
  361. }
  362. }
  363. } else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
  364. if (lfnOrd) {
  365. if (1 == ord && lfnChecksum(dir->name) == chksum) {
  366. goto found;
  367. }
  368. DBG_FAIL_MACRO;
  369. goto fail;
  370. }
  371. if (!memcmp(dir->name, fname->sfn, sizeof(fname->sfn))) {
  372. if (!(fname->flags & FNAME_FLAG_LOST_CHARS)) {
  373. goto found;
  374. }
  375. fnameFound = true;
  376. }
  377. } else {
  378. lfnOrd = 0;
  379. }
  380. }
  381. found:
  382. // Don't open if create only.
  383. if (oflag & O_EXCL) {
  384. DBG_FAIL_MACRO;
  385. goto fail;
  386. }
  387. goto open;
  388. create:
  389. // don't create unless O_CREAT and O_WRITE
  390. if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) {
  391. DBG_FAIL_MACRO;
  392. goto fail;
  393. }
  394. // If at EOF start in next cluster.
  395. if (freeFound == 0) {
  396. freeIndex = curIndex;
  397. }
  398. while (freeFound < freeNeed) {
  399. dir = dirFile->readDirCache();
  400. if (!dir) {
  401. if (dirFile->getError()) {
  402. DBG_FAIL_MACRO;
  403. goto fail;
  404. }
  405. // EOF if no error.
  406. break;
  407. }
  408. freeFound++;
  409. }
  410. while (freeFound < freeNeed) {
  411. // Will fail if FAT16 root.
  412. if (!dirFile->addDirCluster()) {
  413. DBG_FAIL_MACRO;
  414. goto fail;
  415. }
  416. // Done if more than one block per cluster. Max freeNeed is 21.
  417. if (dirFile->m_vol->blocksPerCluster() > 1) {
  418. break;
  419. }
  420. freeFound += 16;
  421. }
  422. if (fnameFound) {
  423. if (!dirFile->lfnUniqueSfn(fname)) {
  424. goto fail;
  425. }
  426. }
  427. if (!dirFile->seekSet(32UL*freeIndex)) {
  428. DBG_FAIL_MACRO;
  429. goto fail;
  430. }
  431. lfnOrd = freeNeed - 1;
  432. for (uint8_t ord = lfnOrd ; ord ; ord--) {
  433. ldir = reinterpret_cast<ldir_t*>(dirFile->readDirCache());
  434. if (!ldir) {
  435. DBG_FAIL_MACRO;
  436. goto fail;
  437. }
  438. dirFile->m_vol->cacheDirty();
  439. ldir->ord = ord == lfnOrd ? LDIR_ORD_LAST_LONG_ENTRY | ord : ord;
  440. ldir->attr = DIR_ATT_LONG_NAME;
  441. ldir->type = 0;
  442. ldir->chksum = lfnChecksum(fname->sfn);
  443. ldir->mustBeZero = 0;
  444. lfnPutName(ldir, fname->lfn, len);
  445. }
  446. curIndex = dirFile->m_curPosition/32;
  447. dir = dirFile->readDirCache();
  448. if (!dir) {
  449. DBG_FAIL_MACRO;
  450. goto fail;
  451. }
  452. // initialize as empty file
  453. memset(dir, 0, sizeof(dir_t));
  454. memcpy(dir->name, fname->sfn, 11);
  455. // Set base-name and extension lower case bits.
  456. dir->reservedNT = (DIR_NT_LC_BASE | DIR_NT_LC_EXT) & fname->flags;
  457. // set timestamps
  458. if (m_dateTime) {
  459. // call user date/time function
  460. m_dateTime(&dir->creationDate, &dir->creationTime);
  461. } else {
  462. // use default date/time
  463. dir->creationDate = FAT_DEFAULT_DATE;
  464. dir->creationTime = FAT_DEFAULT_TIME;
  465. }
  466. dir->lastAccessDate = dir->creationDate;
  467. dir->lastWriteDate = dir->creationDate;
  468. dir->lastWriteTime = dir->creationTime;
  469. // Force write of entry to device.
  470. dirFile->m_vol->cacheDirty();
  471. open:
  472. // open entry in cache.
  473. if (!openCachedEntry(dirFile, curIndex, oflag, lfnOrd)) {
  474. DBG_FAIL_MACRO;
  475. goto fail;
  476. }
  477. return true;
  478. fail:
  479. return false;
  480. }
  481. //------------------------------------------------------------------------------
  482. size_t FatFile::printName(print_t* pr) {
  483. FatFile dirFile;
  484. uint16_t u;
  485. size_t n = 0;
  486. ldir_t* ldir;
  487. if (!isLFN()) {
  488. return printSFN(pr);
  489. }
  490. if (!dirFile.openCluster(this)) {
  491. DBG_FAIL_MACRO;
  492. goto fail;
  493. }
  494. for (uint8_t ord = 1; ord <= m_lfnOrd; ord++) {
  495. if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
  496. DBG_FAIL_MACRO;
  497. goto fail;
  498. }
  499. ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
  500. if (!ldir) {
  501. DBG_FAIL_MACRO;
  502. goto fail;
  503. }
  504. if (ldir->attr != DIR_ATT_LONG_NAME ||
  505. ord != (ldir->ord & 0X1F)) {
  506. DBG_FAIL_MACRO;
  507. goto fail;
  508. }
  509. for (uint8_t i = 0; i < 13; i++) {
  510. u = lfnGetChar(ldir, i);
  511. if (u == 0) {
  512. // End of name.
  513. break;
  514. }
  515. if (u > 0X7E) {
  516. u = '?';
  517. }
  518. pr->write(static_cast<char>(u));
  519. n++;
  520. }
  521. if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
  522. return n;
  523. }
  524. }
  525. // Fall into fail;
  526. DBG_FAIL_MACRO;
  527. fail:
  528. return 0;
  529. }
  530. //------------------------------------------------------------------------------
  531. bool FatFile::remove() {
  532. bool last;
  533. uint8_t chksum;
  534. uint8_t ord;
  535. FatFile dirFile;
  536. dir_t* dir;
  537. ldir_t* ldir;
  538. // Cant' remove not open for write.
  539. if (!isFile() || !(m_flags & O_WRITE)) {
  540. DBG_FAIL_MACRO;
  541. goto fail;
  542. }
  543. // Free any clusters.
  544. if (m_firstCluster && !m_vol->freeChain(m_firstCluster)) {
  545. DBG_FAIL_MACRO;
  546. goto fail;
  547. }
  548. // Cache directory entry.
  549. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  550. if (!dir) {
  551. DBG_FAIL_MACRO;
  552. goto fail;
  553. }
  554. chksum = lfnChecksum(dir->name);
  555. // Mark entry deleted.
  556. dir->name[0] = DIR_NAME_DELETED;
  557. // Set this file closed.
  558. m_attr = FILE_ATTR_CLOSED;
  559. // Write entry to device.
  560. if (!m_vol->cacheSync()) {
  561. DBG_FAIL_MACRO;
  562. goto fail;
  563. }
  564. if (!isLFN()) {
  565. // Done, no LFN entries.
  566. return true;
  567. }
  568. if (!dirFile.openCluster(this)) {
  569. DBG_FAIL_MACRO;
  570. goto fail;
  571. }
  572. for (ord = 1; ord <= m_lfnOrd; ord++) {
  573. if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
  574. DBG_FAIL_MACRO;
  575. goto fail;
  576. }
  577. ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
  578. if (!ldir) {
  579. DBG_FAIL_MACRO;
  580. goto fail;
  581. }
  582. if (ldir->attr != DIR_ATT_LONG_NAME ||
  583. ord != (ldir->ord & 0X1F) ||
  584. chksum != ldir->chksum) {
  585. DBG_FAIL_MACRO;
  586. goto fail;
  587. }
  588. last = ldir->ord & LDIR_ORD_LAST_LONG_ENTRY;
  589. ldir->ord = DIR_NAME_DELETED;
  590. m_vol->cacheDirty();
  591. if (last) {
  592. if (!m_vol->cacheSync()) {
  593. DBG_FAIL_MACRO;
  594. goto fail;
  595. }
  596. return true;
  597. }
  598. }
  599. // Fall into fail.
  600. DBG_FAIL_MACRO;
  601. fail:
  602. return false;
  603. }
  604. //------------------------------------------------------------------------------
  605. bool FatFile::lfnUniqueSfn(fname_t* fname) {
  606. const uint8_t FIRST_HASH_SEQ = 2; // min value is 2
  607. uint8_t pos = fname->seqPos;;
  608. dir_t *dir;
  609. uint16_t hex;
  610. DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS));
  611. DBG_HALT_IF(fname->sfn[pos] != '~' && fname->sfn[pos + 1] != '1');
  612. for (uint8_t seq = 2; seq < 100; seq++) {
  613. if (seq < FIRST_HASH_SEQ) {
  614. fname->sfn[pos + 1] = '0' + seq;
  615. } else {
  616. DBG_PRINT_IF(seq > FIRST_HASH_SEQ);
  617. hex = Bernstein(seq + fname->len, fname->lfn, fname->len);
  618. if (pos > 3) {
  619. // Make space in name for ~HHHH.
  620. pos = 3;
  621. }
  622. for (uint8_t i = pos + 4 ; i > pos; i--) {
  623. uint8_t h = hex & 0XF;
  624. fname->sfn[i] = h < 10 ? h + '0' : h + 'A' - 10;
  625. hex >>= 4;
  626. }
  627. }
  628. fname->sfn[pos] = '~';
  629. rewind();
  630. while (1) {
  631. dir = readDirCache(true);
  632. if (!dir) {
  633. if (!getError()) {
  634. // At EOF and name not found if no error.
  635. goto done;
  636. }
  637. DBG_FAIL_MACRO;
  638. goto fail;
  639. }
  640. if (dir->name[0] == DIR_NAME_FREE) {
  641. goto done;
  642. }
  643. if (DIR_IS_FILE_OR_SUBDIR(dir) && !memcmp(fname->sfn, dir->name, 11)) {
  644. // Name found - try another.
  645. break;
  646. }
  647. }
  648. }
  649. // fall inti fail - too many tries.
  650. DBG_FAIL_MACRO;
  651. fail:
  652. return false;
  653. done:
  654. return true;
  655. }
  656. #endif // #if USE_LONG_FILE_NAMES