ExFatPartition.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /**
  2. * Copyright (c) 2011-2022 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 "ExFatPartition.cpp"
  26. #include "../common/DebugMacros.h"
  27. #include "../common/PartitionTable.h"
  28. #include "ExFatLib.h"
  29. //------------------------------------------------------------------------------
  30. // return 0 if error, 1 if no space, else start cluster.
  31. uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
  32. uint32_t start = cluster ? cluster - 2 : m_bitmapStart;
  33. if (start >= m_clusterCount) {
  34. start = 0;
  35. }
  36. uint32_t endAlloc = start;
  37. uint32_t bgnAlloc = start;
  38. uint16_t sectorSize = 1 << m_bytesPerSectorShift;
  39. size_t i = (start >> 3) & (sectorSize - 1);
  40. uint8_t* cache;
  41. uint8_t mask = 1 << (start & 7);
  42. while (true) {
  43. uint32_t sector = m_clusterHeapStartSector +
  44. (endAlloc >> (m_bytesPerSectorShift + 3));
  45. cache = bitmapCachePrepare(sector, FsCache::CACHE_FOR_READ);
  46. if (!cache) {
  47. return 0;
  48. }
  49. for (; i < sectorSize; i++) {
  50. for (; mask; mask <<= 1) {
  51. endAlloc++;
  52. if (!(mask & cache[i])) {
  53. if ((endAlloc - bgnAlloc) == count) {
  54. if (cluster == 0 && count == 1) {
  55. // Start at found sector. bitmapModify may increase this.
  56. m_bitmapStart = bgnAlloc;
  57. }
  58. return bgnAlloc + 2;
  59. }
  60. } else {
  61. bgnAlloc = endAlloc;
  62. }
  63. if (endAlloc == start) {
  64. return 1;
  65. }
  66. if (endAlloc >= m_clusterCount) {
  67. endAlloc = bgnAlloc = 0;
  68. i = sectorSize;
  69. break;
  70. }
  71. }
  72. mask = 1;
  73. }
  74. i = 0;
  75. }
  76. return 0;
  77. }
  78. //------------------------------------------------------------------------------
  79. bool ExFatPartition::bitmapModify(uint32_t cluster,
  80. uint32_t count, bool value) {
  81. uint32_t sector;
  82. uint32_t start = cluster - 2;
  83. size_t i;
  84. uint8_t* cache;
  85. uint8_t mask;
  86. cluster -= 2;
  87. if ((start + count) > m_clusterCount) {
  88. DBG_FAIL_MACRO;
  89. goto fail;
  90. }
  91. if (value) {
  92. if (start <= m_bitmapStart && m_bitmapStart < (start + count)) {
  93. m_bitmapStart = (start + count) < m_clusterCount ? start + count : 0;
  94. }
  95. } else {
  96. if (start < m_bitmapStart) {
  97. m_bitmapStart = start;
  98. }
  99. }
  100. mask = 1 << (start & 7);
  101. sector = m_clusterHeapStartSector +
  102. (start >> (m_bytesPerSectorShift + 3));
  103. i = (start >> 3) & m_sectorMask;
  104. while (true) {
  105. cache = bitmapCachePrepare(sector++, FsCache::CACHE_FOR_WRITE);
  106. if (!cache) {
  107. DBG_FAIL_MACRO;
  108. goto fail;
  109. }
  110. for (; i < m_bytesPerSector; i++) {
  111. for (; mask; mask <<= 1) {
  112. if (value == static_cast<bool>(cache[i] & mask)) {
  113. DBG_FAIL_MACRO;
  114. goto fail;
  115. }
  116. cache[i] ^= mask;
  117. if (--count == 0) {
  118. return true;
  119. }
  120. }
  121. mask = 1;
  122. }
  123. i = 0;
  124. }
  125. fail:
  126. return false;
  127. }
  128. //------------------------------------------------------------------------------
  129. uint32_t ExFatPartition::chainSize(uint32_t cluster) {
  130. uint32_t n = 0;
  131. int8_t status;
  132. do {
  133. status = fatGet(cluster, & cluster);
  134. if (status < 0) return 0;
  135. n++;
  136. } while (status);
  137. return n;
  138. }
  139. //------------------------------------------------------------------------------
  140. uint8_t* ExFatPartition::dirCache(DirPos_t* pos, uint8_t options) {
  141. uint32_t sector = clusterStartSector(pos->cluster);
  142. sector += (m_clusterMask & pos->position) >> m_bytesPerSectorShift;
  143. uint8_t* cache = dataCachePrepare(sector, options);
  144. return cache ? cache + (pos->position & m_sectorMask) : nullptr;
  145. }
  146. //------------------------------------------------------------------------------
  147. // return -1 error, 0 EOC, 1 OK
  148. int8_t ExFatPartition::dirSeek(DirPos_t* pos, uint32_t offset) {
  149. int8_t status;
  150. uint32_t tmp = (m_clusterMask & pos->position) + offset;
  151. pos->position += offset;
  152. tmp >>= bytesPerClusterShift();
  153. while (tmp--) {
  154. if (pos->isContiguous) {
  155. pos->cluster++;
  156. } else {
  157. status = fatGet(pos->cluster, &pos->cluster);
  158. if (status != 1) {
  159. return status;
  160. }
  161. }
  162. }
  163. return 1;
  164. }
  165. //------------------------------------------------------------------------------
  166. // return -1 error, 0 EOC, 1 OK
  167. int8_t ExFatPartition::fatGet(uint32_t cluster, uint32_t* value) {
  168. uint8_t* cache;
  169. uint32_t next;
  170. uint32_t sector;
  171. if (cluster > (m_clusterCount + 1)) {
  172. DBG_FAIL_MACRO;
  173. return -1;
  174. }
  175. sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 2));
  176. cache = dataCachePrepare(sector, FsCache::CACHE_FOR_READ);
  177. if (!cache) {
  178. return -1;
  179. }
  180. next = getLe32(cache + ((cluster << 2) & m_sectorMask));
  181. if (next == EXFAT_EOC) {
  182. return 0;
  183. }
  184. *value = next;
  185. return 1;
  186. }
  187. //------------------------------------------------------------------------------
  188. bool ExFatPartition::fatPut(uint32_t cluster, uint32_t value) {
  189. uint32_t sector;
  190. uint8_t* cache;
  191. if (cluster < 2 || cluster > (m_clusterCount + 1)) {
  192. DBG_FAIL_MACRO;
  193. goto fail;
  194. }
  195. sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 2));
  196. cache = dataCachePrepare(sector, FsCache::CACHE_FOR_WRITE);
  197. if (!cache) {
  198. DBG_FAIL_MACRO;
  199. goto fail;
  200. }
  201. setLe32(cache + ((cluster << 2) & m_sectorMask), value);
  202. return true;
  203. fail:
  204. return false;
  205. }
  206. //------------------------------------------------------------------------------
  207. bool ExFatPartition::freeChain(uint32_t cluster) {
  208. uint32_t next;
  209. uint32_t start = cluster;
  210. int8_t status;
  211. do {
  212. status = fatGet(cluster, &next);
  213. if (status < 0) {
  214. DBG_FAIL_MACRO;
  215. goto fail;
  216. }
  217. if (!fatPut(cluster, 0)) {
  218. DBG_FAIL_MACRO;
  219. goto fail;
  220. }
  221. if (status == 0 || (cluster + 1) != next) {
  222. if (!bitmapModify(start, cluster - start + 1, 0)) {
  223. DBG_FAIL_MACRO;
  224. goto fail;
  225. }
  226. start = next;
  227. }
  228. cluster = next;
  229. } while (status);
  230. return true;
  231. fail:
  232. return false;
  233. }
  234. //------------------------------------------------------------------------------
  235. int32_t ExFatPartition::freeClusterCount() {
  236. uint32_t nc = 0;
  237. uint32_t sector = m_clusterHeapStartSector;
  238. uint32_t usedCount = 0;
  239. uint8_t* cache;
  240. while (true) {
  241. cache = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ);
  242. if (!cache) {
  243. return -1;
  244. }
  245. for (size_t i = 0; i < m_bytesPerSector; i++) {
  246. if (cache[i] == 0XFF) {
  247. usedCount+= 8;
  248. } else if (cache[i]) {
  249. for (uint8_t mask = 1; mask ; mask <<=1) {
  250. if ((mask & cache[i])) {
  251. usedCount++;
  252. }
  253. }
  254. }
  255. nc += 8;
  256. if (nc >= m_clusterCount) {
  257. return m_clusterCount - usedCount;
  258. }
  259. }
  260. }
  261. }
  262. //------------------------------------------------------------------------------
  263. bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
  264. pbs_t* pbs;
  265. BpbExFat_t* bpb;
  266. m_fatType = 0;
  267. m_blockDev = dev;
  268. cacheInit(m_blockDev);
  269. // if part == 0 assume super floppy with FAT boot sector in sector zero
  270. // if part > 0 read MBR / GPT partition table
  271. if (part) {
  272. volStart = partitionTableGetVolumeStartSector(m_dataCache, part);
  273. if (!volStart) {
  274. DBG_FAIL_MACRO;
  275. goto fail;
  276. }
  277. }
  278. pbs = reinterpret_cast<pbs_t*>
  279. (dataCachePrepare(volStart, FsCache::CACHE_FOR_READ));
  280. if (!pbs) {
  281. DBG_FAIL_MACRO;
  282. goto fail;
  283. }
  284. if (strncmp(pbs->oemName, "EXFAT", 5)) {
  285. DBG_FAIL_MACRO;
  286. goto fail;
  287. }
  288. bpb = reinterpret_cast<BpbExFat_t*>(pbs->bpb);
  289. if (bpb->bytesPerSectorShift != m_bytesPerSectorShift) {
  290. DBG_FAIL_MACRO;
  291. goto fail;
  292. }
  293. m_fatStartSector = volStart + getLe32(bpb->fatOffset);
  294. m_fatLength = getLe32(bpb->fatLength);
  295. m_clusterHeapStartSector = volStart + getLe32(bpb->clusterHeapOffset);
  296. m_clusterCount = getLe32(bpb->clusterCount);
  297. m_rootDirectoryCluster = getLe32(bpb->rootDirectoryCluster);
  298. m_sectorsPerClusterShift = bpb->sectorsPerClusterShift;
  299. m_bytesPerCluster = 1UL << (m_bytesPerSectorShift + m_sectorsPerClusterShift);
  300. m_clusterMask = m_bytesPerCluster - 1;
  301. // Set m_bitmapStart to first free cluster.
  302. m_bitmapStart = 0;
  303. bitmapFind(0, 1);
  304. m_fatType = FAT_TYPE_EXFAT;
  305. return true;
  306. fail:
  307. return false;
  308. }
  309. //------------------------------------------------------------------------------
  310. uint32_t ExFatPartition::rootLength() {
  311. uint32_t nc = chainSize(m_rootDirectoryCluster);
  312. return nc << bytesPerClusterShift();
  313. }