Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

713 lines
18KB

  1. /**
  2. * Copyright (c) 2011-2019 Bill Greiman
  3. * This file is part of the SdFat library for SD memory cards.
  4. *
  5. * MIT License
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #define DBG_FILE "ExFatFile.cpp"
  26. #include "../common/DebugMacros.h"
  27. #include "ExFatFile.h"
  28. #include "ExFatVolume.h"
  29. #include "upcase.h"
  30. //-----------------------------------------------------------------------------
  31. bool ExFatFile::close() {
  32. bool rtn = sync();
  33. m_attributes = FILE_ATTR_CLOSED;
  34. m_flags = 0;
  35. return rtn;
  36. }
  37. //------------------------------------------------------------------------------
  38. void ExFatFile::fgetpos(fspos_t* pos) {
  39. pos->position = m_curPosition;
  40. pos->cluster = m_curCluster;
  41. }
  42. //------------------------------------------------------------------------------
  43. int ExFatFile::fgets(char* str, int num, char* delim) {
  44. char ch;
  45. int n = 0;
  46. int r = -1;
  47. while ((n + 1) < num && (r = read(&ch, 1)) == 1) {
  48. // delete CR
  49. if (ch == '\r') {
  50. continue;
  51. }
  52. str[n++] = ch;
  53. if (!delim) {
  54. if (ch == '\n') {
  55. break;
  56. }
  57. } else {
  58. if (strchr(delim, ch)) {
  59. break;
  60. }
  61. }
  62. }
  63. if (r < 0) {
  64. // read error
  65. return -1;
  66. }
  67. str[n] = '\0';
  68. return n;
  69. }
  70. //------------------------------------------------------------------------------
  71. void ExFatFile::fsetpos(const fspos_t* pos) {
  72. m_curPosition = pos->position;
  73. m_curCluster = pos->cluster;
  74. }
  75. //-----------------------------------------------------------------------------
  76. size_t ExFatFile::getName(ExChar_t *name, size_t length) {
  77. DirName_t* dn;
  78. DirPos_t pos = m_dirPos;
  79. size_t n = 0;
  80. if (!isOpen()) {
  81. DBG_FAIL_MACRO;
  82. goto fail;
  83. }
  84. for (uint8_t is = 1; is < m_setCount; is++) {
  85. if (m_vol->dirSeek(&pos, is == 1 ? 64: 32) != 1) {
  86. DBG_FAIL_MACRO;
  87. goto fail;
  88. }
  89. dn = reinterpret_cast<DirName_t*>
  90. (m_vol->dirCache(&pos, FsCache::CACHE_FOR_READ));
  91. if (!dn || dn->type != EXFAT_TYPE_NAME) {
  92. DBG_FAIL_MACRO;
  93. goto fail;
  94. }
  95. for (uint8_t in = 0; in < 15; in++) {
  96. if ((n + 1) >= length) {
  97. goto done;
  98. }
  99. uint16_t c = getLe16(dn->unicode + 2*in);
  100. name[n++] = sizeof(ExChar_t) > 1 || c < 0X7F ? c : '?';
  101. }
  102. }
  103. done:
  104. name[n] = 0;
  105. return n;
  106. fail:
  107. *name = 0;
  108. return 0;
  109. }
  110. //-----------------------------------------------------------------------------
  111. bool ExFatFile::open(const ExChar_t* path, int oflag) {
  112. return open(ExFatVolume::cwv(), path, oflag);
  113. }
  114. //-----------------------------------------------------------------------------
  115. bool ExFatFile::open(ExFatVolume* vol, const ExChar_t* path, int oflag) {
  116. return vol && open(vol->vwd(), path, oflag);
  117. }
  118. //------------------------------------------------------------------------------
  119. bool ExFatFile::open(ExFatFile* dirFile, const ExChar_t* path, oflag_t oflag) {
  120. ExFatFile tmpDir;
  121. ExName_t fname;
  122. // error if already open
  123. if (isOpen() || !dirFile->isDir()) {
  124. DBG_FAIL_MACRO;
  125. goto fail;
  126. }
  127. if (isDirSeparator(*path)) {
  128. while (isDirSeparator(*path)) {
  129. path++;
  130. }
  131. if (*path == 0) {
  132. return openRoot(dirFile->m_vol);
  133. }
  134. if (!tmpDir.openRoot(dirFile->m_vol)) {
  135. DBG_FAIL_MACRO;
  136. goto fail;
  137. }
  138. dirFile = &tmpDir;
  139. }
  140. while (1) {
  141. if (!parsePathName(path, &fname, &path)) {
  142. DBG_FAIL_MACRO;
  143. goto fail;
  144. }
  145. if (*path == 0) {
  146. break;
  147. }
  148. if (!open(dirFile, &fname, O_RDONLY)) {
  149. DBG_FAIL_MACRO;
  150. goto fail;
  151. }
  152. tmpDir = *this;
  153. dirFile = &tmpDir;
  154. close();
  155. }
  156. return open(dirFile, &fname, oflag);
  157. fail:
  158. return false;
  159. }
  160. //------------------------------------------------------------------------------
  161. bool ExFatFile::open(ExFatFile* dirFile, uint32_t index, oflag_t oflag) {
  162. if (dirFile->seekSet(32*index) && openNext(dirFile, oflag)) {
  163. if (dirIndex() == index) {
  164. return true;
  165. }
  166. close();
  167. DBG_FAIL_MACRO;
  168. }
  169. return false;
  170. }
  171. //-----------------------------------------------------------------------------
  172. bool ExFatFile::openNext(ExFatFile* dir, oflag_t oflag) {
  173. if (isOpen() || !dir->isDir() || (dir->curPosition() & 0X1F)) {
  174. DBG_FAIL_MACRO;
  175. goto fail;
  176. }
  177. return openRootFile(dir, nullptr, 0, oflag);
  178. fail:
  179. return false;
  180. }
  181. //------------------------------------------------------------------------------
  182. bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name,
  183. uint8_t nameLength, oflag_t oflag) {
  184. int n;
  185. uint8_t nameOffset = 0;
  186. uint8_t nCmp;
  187. uint8_t modeFlags;
  188. uint16_t nameHash = 0;
  189. uint32_t curCluster __attribute__((unused));
  190. uint8_t* cache __attribute__((unused));
  191. DirPos_t freePos __attribute__((unused));
  192. DirFile_t* dirFile;
  193. DirStream_t* dirStream;
  194. DirName_t* dirName;
  195. uint8_t buf[32];
  196. uint8_t freeCount = 0;
  197. uint8_t freeNeed;
  198. bool inSet = false;
  199. // error if already open
  200. if (isOpen() || !dir->isDir()) {
  201. DBG_FAIL_MACRO;
  202. goto fail;
  203. }
  204. switch (oflag & O_ACCMODE) {
  205. case O_RDONLY:
  206. modeFlags = FILE_FLAG_READ;
  207. break;
  208. case O_WRONLY:
  209. modeFlags = FILE_FLAG_WRITE;
  210. break;
  211. case O_RDWR:
  212. modeFlags = FILE_FLAG_READ | FILE_FLAG_WRITE;
  213. break;
  214. default:
  215. DBG_FAIL_MACRO;
  216. goto fail;
  217. }
  218. modeFlags |= oflag & O_APPEND ? FILE_FLAG_APPEND : 0;
  219. if (name) {
  220. nameHash = exFatHashName(name, nameLength, 0);
  221. dir->rewind();
  222. }
  223. freeNeed = 2 + (nameLength + 14)/15;
  224. while (1) {
  225. n = dir->read(buf, 32);
  226. if (n == 0) {
  227. goto create;
  228. }
  229. if (n != 32) {
  230. DBG_FAIL_MACRO;
  231. goto fail;
  232. }
  233. if (!(buf[0] & 0x80)) {
  234. if (freeCount == 0) {
  235. freePos.position = dir->curPosition() - 32;
  236. freePos.cluster = dir->curCluster();
  237. }
  238. if (freeCount < freeNeed) {
  239. freeCount++;
  240. }
  241. if (!buf[0]) {
  242. goto create;
  243. }
  244. } else if (!inSet) {
  245. if (freeCount < freeNeed) {
  246. freeCount = 0;
  247. }
  248. if (buf[0] != EXFAT_TYPE_FILE) {
  249. continue;
  250. }
  251. inSet = true;
  252. }
  253. switch (buf[0]) {
  254. case EXFAT_TYPE_FILE:
  255. memset(this, 0, sizeof(ExFatFile));
  256. dirFile = reinterpret_cast<DirFile_t*>(buf);
  257. m_setCount = dirFile->setCount;
  258. m_attributes = getLe16(dirFile->attributes) & FILE_ATTR_COPY;
  259. if (!(m_attributes & EXFAT_ATTRIB_DIRECTORY)) {
  260. m_attributes |= FILE_ATTR_FILE;
  261. }
  262. m_vol = dir->volume();
  263. m_dirPos.cluster = dir->curCluster();
  264. m_dirPos.position = dir->curPosition() - 32;
  265. m_dirPos.isContiguous = dir->isContiguous();
  266. break;
  267. case EXFAT_TYPE_STREAM:
  268. dirStream = reinterpret_cast<DirStream_t*>(buf);
  269. m_flags = modeFlags;
  270. if (dirStream->flags & EXFAT_FLAG_CONTIGUOUS) {
  271. m_flags |= FILE_FLAG_CONTIGUOUS;
  272. }
  273. nameOffset = 0;
  274. m_validLength = getLe64(dirStream->validLength);
  275. m_firstCluster = getLe32(dirStream->firstCluster);
  276. m_dataLength = getLe64(dirStream->dataLength);
  277. if (!name) {
  278. goto found;
  279. }
  280. if (nameLength != dirStream->nameLength ||
  281. nameHash != getLe16(dirStream->nameHash)) {
  282. inSet = false;
  283. break;
  284. }
  285. break;
  286. case EXFAT_TYPE_NAME:
  287. dirName = reinterpret_cast<DirName_t*>(buf);
  288. nCmp = nameLength - nameOffset;
  289. if (nCmp > 15) {
  290. nCmp = 15;
  291. }
  292. if (!exFatCmpName(dirName, name, nameOffset, nCmp)) {
  293. inSet = false;
  294. break;
  295. }
  296. nameOffset += nCmp;
  297. if (nameOffset == nameLength) {
  298. goto found;
  299. }
  300. break;
  301. default:
  302. break;
  303. }
  304. }
  305. found:
  306. // Don't open if create only.
  307. if (oflag & O_EXCL) {
  308. DBG_FAIL_MACRO;
  309. goto fail;
  310. }
  311. // Write, truncate, or at end is an error for a directory or read-only file.
  312. if ((oflag & (O_TRUNC | O_AT_END)) || (m_flags & FILE_FLAG_WRITE)) {
  313. if (isSubDir() || isReadOnly() || READ_ONLY) {
  314. DBG_FAIL_MACRO;
  315. goto fail;
  316. }
  317. }
  318. #if !READ_ONLY
  319. if (oflag & O_TRUNC) {
  320. if (!(m_flags & FILE_FLAG_WRITE)) {
  321. DBG_FAIL_MACRO;
  322. goto fail;
  323. }
  324. if (!truncate(0)) {
  325. DBG_FAIL_MACRO;
  326. goto fail;
  327. }
  328. } else if ((oflag & O_AT_END) && !seekSet(fileSize())) {
  329. DBG_FAIL_MACRO;
  330. goto fail;
  331. }
  332. #endif // READ_ONLY
  333. return true;
  334. create:
  335. #if READ_ONLY
  336. DBG_FAIL_MACRO;
  337. goto fail;
  338. #else // READ_ONLY
  339. // don't create unless O_CREAT and write
  340. if (!(oflag & O_CREAT) || !(modeFlags & FILE_FLAG_WRITE) || !name) {
  341. DBG_FAIL_MACRO;
  342. goto fail;
  343. }
  344. while (freeCount < freeNeed) {
  345. n = dir->read(buf, 32);
  346. if (n == 0) {
  347. curCluster = dir->m_curCluster;
  348. if (!dir->addDirCluster()) {
  349. DBG_FAIL_MACRO;
  350. goto fail;
  351. }
  352. dir->m_curCluster = curCluster;
  353. continue;
  354. }
  355. if (n != 32) {
  356. DBG_FAIL_MACRO;
  357. goto fail;
  358. }
  359. if (freeCount == 0) {
  360. freePos.position = dir->curPosition() - 32;
  361. freePos.cluster = dir->curCluster();
  362. }
  363. freeCount++;
  364. }
  365. freePos.isContiguous = dir->isContiguous();
  366. memset(this, 0, sizeof(ExFatFile));
  367. m_vol = dir->volume();
  368. m_attributes = FILE_ATTR_FILE;
  369. m_dirPos = freePos;
  370. for (uint8_t i = 0; i < freeNeed; i++) {
  371. if (i) {
  372. if (1 != m_vol->dirSeek(&freePos, 32)) {
  373. DBG_FAIL_MACRO;
  374. goto fail;
  375. }
  376. }
  377. cache = m_vol->dirCache(&freePos, FsCache::CACHE_FOR_WRITE);
  378. if (!cache || (cache[0] & 0x80)) {
  379. DBG_FAIL_MACRO;
  380. goto fail;
  381. }
  382. memset(cache, 0 , 32);
  383. if (i == 0) {
  384. dirFile = reinterpret_cast<DirFile_t*>(cache);
  385. dirFile->type = EXFAT_TYPE_FILE;
  386. m_setCount = freeNeed - 1;
  387. dirFile->setCount = m_setCount;
  388. if (FsDateTime::callback) {
  389. uint16_t date, time;
  390. uint8_t ms10;
  391. FsDateTime::callback(&date, &time, &ms10);
  392. dirFile->createTimeMs = ms10;
  393. setLe16(dirFile->createTime, time);
  394. setLe16(dirFile->createDate, date);
  395. }
  396. } else if (i == 1) {
  397. dirStream = reinterpret_cast<DirStream_t*>(cache);
  398. dirStream->type = EXFAT_TYPE_STREAM;
  399. dirStream->flags = EXFAT_FLAG_ALWAYS1 | EXFAT_FLAG_CONTIGUOUS;
  400. m_flags = modeFlags | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY;
  401. dirStream->nameLength = nameLength;
  402. setLe16(dirStream->nameHash, nameHash);
  403. } else {
  404. dirName = reinterpret_cast<DirName_t*>(cache);
  405. dirName->type = EXFAT_TYPE_NAME;
  406. nameOffset = 15*(i - 2);
  407. nCmp = nameLength - nameOffset;
  408. if (nCmp > 15) {
  409. nCmp = 15;
  410. }
  411. for (size_t k = 0; k < nCmp; k++) {
  412. setLe16(dirName->unicode + 2*k, name[k + nameOffset]);
  413. }
  414. }
  415. }
  416. return sync();
  417. #endif // READ_ONLY
  418. fail:
  419. // close file
  420. m_attributes = FILE_ATTR_CLOSED;
  421. m_flags = 0;
  422. return false;
  423. }
  424. //-----------------------------------------------------------------------------
  425. bool ExFatFile::openRoot(ExFatVolume* vol) {
  426. if (isOpen()) {
  427. DBG_FAIL_MACRO;
  428. goto fail;
  429. }
  430. memset(this, 0, sizeof(ExFatFile));
  431. m_attributes = FILE_ATTR_ROOT;
  432. m_vol = vol;
  433. m_flags = FILE_FLAG_READ;
  434. return true;
  435. fail:
  436. return false;
  437. }
  438. //------------------------------------------------------------------------------
  439. bool ExFatFile::parsePathName(const ExChar_t* path,
  440. ExName_t* fname, const ExChar_t** ptr) {
  441. ExChar_t c;
  442. int end;
  443. int len = 0;
  444. // Skip leading spaces.
  445. while (*path == ' ') {
  446. path++;
  447. }
  448. fname->lfn = path;
  449. for (len = 0; ; len++) {
  450. c = path[len];
  451. if (c == 0 || isDirSeparator(c)) {
  452. break;
  453. }
  454. if (!lfnLegalChar(c)) {
  455. return false;
  456. }
  457. }
  458. // Advance to next path component.
  459. for (end = len; path[end] == ' ' || isDirSeparator(path[end]); end++) {}
  460. *ptr = &path[end];
  461. // Back over spaces and dots.
  462. while (len) {
  463. c = path[len - 1];
  464. if (c != '.' && c != ' ') {
  465. break;
  466. }
  467. len--;
  468. }
  469. // Max length of LFN is 255.
  470. if (len > EXFAT_MAX_NAME_LENGTH) {
  471. return false;
  472. }
  473. fname->len = len;
  474. return true;
  475. }
  476. //-----------------------------------------------------------------------------
  477. int ExFatFile::peek() {
  478. uint64_t curPosition = m_curPosition;
  479. uint32_t curCluster = m_curCluster;
  480. int c = read();
  481. m_curPosition = curPosition;
  482. m_curCluster = curCluster;
  483. return c;
  484. }
  485. //-----------------------------------------------------------------------------
  486. size_t ExFatFile::printName(print_t* pr) {
  487. DirName_t* dn;
  488. DirPos_t pos = m_dirPos;
  489. size_t n = 0;
  490. uint8_t in;
  491. uint8_t buf[15];
  492. if (!isOpen()) {
  493. DBG_FAIL_MACRO;
  494. goto fail;
  495. }
  496. for (uint8_t is = 1; is < m_setCount; is++) {
  497. if (m_vol->dirSeek(&pos, is == 1 ? 64: 32) != 1) {
  498. DBG_FAIL_MACRO;
  499. goto fail;
  500. }
  501. dn = reinterpret_cast<DirName_t*>
  502. (m_vol->dirCache(&pos, FsCache::CACHE_FOR_READ));
  503. if (!dn || dn->type != EXFAT_TYPE_NAME) {
  504. DBG_FAIL_MACRO;
  505. goto fail;
  506. }
  507. for (in = 0; in < 15; in++) {
  508. uint16_t c = getLe16(dn->unicode + 2*in);
  509. if (!c) {
  510. break;;
  511. }
  512. buf[in] = c < 0X7f ? c : '?';
  513. n++;
  514. }
  515. pr->write(buf, in);
  516. }
  517. return n;
  518. fail:
  519. return 0;
  520. }
  521. //-----------------------------------------------------------------------------
  522. int ExFatFile::read(void* buf, size_t count) {
  523. uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
  524. int8_t fg;
  525. size_t toRead = count;
  526. size_t n;
  527. uint8_t* cache;
  528. uint16_t sectorOffset;
  529. uint32_t sector;
  530. uint32_t clusterOffset;
  531. if (!isReadable()) {
  532. DBG_FAIL_MACRO;
  533. goto fail;
  534. }
  535. if (isContiguous() || isFile()) {
  536. if ((m_curPosition + count) > m_validLength) {
  537. count = toRead = m_validLength - m_curPosition;
  538. }
  539. }
  540. while (toRead) {
  541. clusterOffset = m_curPosition & m_vol->clusterMask();
  542. sectorOffset = clusterOffset & m_vol->sectorMask();
  543. if (clusterOffset == 0) {
  544. if (m_curPosition == 0) {
  545. m_curCluster = isRoot()
  546. ? m_vol->rootDirectoryCluster() : m_firstCluster;
  547. } else if (isContiguous()) {
  548. m_curCluster++;
  549. } else {
  550. fg = m_vol->fatGet(m_curCluster, &m_curCluster);
  551. if (fg < 0) {
  552. DBG_FAIL_MACRO;
  553. goto fail;
  554. }
  555. if (fg == 0) {
  556. // EOF if directory.
  557. if (isDir()) {
  558. break;
  559. }
  560. DBG_FAIL_MACRO;
  561. goto fail;
  562. }
  563. }
  564. }
  565. sector = m_vol->clusterStartSector(m_curCluster) +
  566. (clusterOffset >> m_vol->bytesPerSectorShift());
  567. if (sectorOffset != 0 || toRead < m_vol->bytesPerSector()
  568. || sector == m_vol->dataCacheSector()) {
  569. n = m_vol->bytesPerSector() - sectorOffset;
  570. if (n > toRead) {
  571. n = toRead;
  572. }
  573. // read sector to cache and copy data to caller
  574. cache = m_vol->dataCacheGet(sector, FsCache::CACHE_FOR_READ);
  575. if (!cache) {
  576. DBG_FAIL_MACRO;
  577. goto fail;
  578. }
  579. uint8_t* src = cache + sectorOffset;
  580. memcpy(dst, src, n);
  581. #if USE_MULTI_SECTOR_IO
  582. } else if (toRead >= 2*m_vol->bytesPerSector()) {
  583. uint32_t ns = toRead >> m_vol->bytesPerSectorShift();
  584. // Limit writes to current cluster.
  585. uint32_t maxNs = m_vol->sectorsPerCluster()
  586. - (clusterOffset >> m_vol->bytesPerSectorShift());
  587. if (ns > maxNs) {
  588. ns = maxNs;
  589. }
  590. n = ns << m_vol->bytesPerSectorShift();
  591. // Check for cache sector in read range.
  592. if (sector <= m_vol->dataCacheSector()
  593. && m_vol->dataCacheSector() < (sector + ns)) {
  594. // Flush cache if cache sector is in the range.
  595. if (!m_vol->dataCacheSync()) {
  596. DBG_FAIL_MACRO;
  597. goto fail;
  598. }
  599. }
  600. if (!m_vol->readSectors(sector, dst, ns)) {
  601. DBG_FAIL_MACRO;
  602. goto fail;
  603. }
  604. #endif // USE_MULTI_SECTOR_IO
  605. } else {
  606. // read single sector
  607. n = m_vol->bytesPerSector();
  608. if (!m_vol->readSector(sector, dst)) {
  609. DBG_FAIL_MACRO;
  610. goto fail;
  611. }
  612. }
  613. dst += n;
  614. m_curPosition += n;
  615. toRead -= n;
  616. }
  617. return count - toRead;
  618. fail:
  619. m_error |= READ_ERROR;
  620. return -1;
  621. }
  622. //------------------------------------------------------------------------------
  623. bool ExFatFile::remove(const ExChar_t* path) {
  624. ExFatFile file;
  625. if (!file.open(this, path, O_WRONLY)) {
  626. DBG_FAIL_MACRO;
  627. goto fail;
  628. }
  629. return file.remove();
  630. fail:
  631. return false;
  632. }
  633. //------------------------------------------------------------------------------
  634. bool ExFatFile::seekSet(uint64_t pos) {
  635. uint32_t nCur;
  636. uint32_t nNew;
  637. uint32_t tmp = m_curCluster;
  638. // error if file not open
  639. if (!isOpen()) {
  640. DBG_FAIL_MACRO;
  641. goto fail;
  642. }
  643. // Optimize O_APPEND writes.
  644. if (pos == m_curPosition) {
  645. return true;
  646. }
  647. if (pos == 0) {
  648. // set position to start of file
  649. m_curCluster = 0;
  650. goto done;
  651. }
  652. if (isFile()) {
  653. if (pos > m_validLength) {
  654. DBG_FAIL_MACRO;
  655. goto fail;
  656. }
  657. }
  658. // calculate cluster index for new position
  659. nNew = (pos - 1) >> m_vol->bytesPerClusterShift();
  660. if (isContiguous()) {
  661. m_curCluster = m_firstCluster + nNew;
  662. goto done;
  663. }
  664. // calculate cluster index for current position
  665. nCur = (m_curPosition - 1) >> m_vol->bytesPerClusterShift();
  666. if (nNew < nCur || m_curPosition == 0) {
  667. // must follow chain from first cluster
  668. m_curCluster = isRoot() ? m_vol->rootDirectoryCluster() : m_firstCluster;
  669. } else {
  670. // advance from curPosition
  671. nNew -= nCur;
  672. }
  673. while (nNew--) {
  674. if (m_vol->fatGet(m_curCluster, &m_curCluster) <= 0) {
  675. DBG_FAIL_MACRO;
  676. goto fail;
  677. }
  678. }
  679. done:
  680. m_curPosition = pos;
  681. return true;
  682. fail:
  683. m_curCluster = tmp;
  684. return false;
  685. }