Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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