ExFatPartition.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. #ifndef ExFatPartition_h
  26. #define ExFatPartition_h
  27. /**
  28. * \file
  29. * \brief ExFatPartition include file.
  30. */
  31. #include "../common/SysCall.h"
  32. #include "../common/FsBlockDevice.h"
  33. #include "../common/FsCache.h"
  34. #include "../common/FsStructs.h"
  35. /** Set EXFAT_READ_ONLY non-zero for read only */
  36. #ifndef EXFAT_READ_ONLY
  37. #define EXFAT_READ_ONLY 0
  38. #endif // EXFAT_READ_ONLY
  39. /** Type for exFAT partition */
  40. const uint8_t FAT_TYPE_EXFAT = 64;
  41. class ExFatFile;
  42. //------------------------------------------------------------------------------
  43. /**
  44. * \struct DirPos_t
  45. * \brief Internal type for position in directory file.
  46. */
  47. struct DirPos_t {
  48. /** current cluster */
  49. uint32_t cluster;
  50. /** offset */
  51. uint32_t position;
  52. /** directory is contiguous */
  53. bool isContiguous;
  54. };
  55. //==============================================================================
  56. /**
  57. * \class ExFatPartition
  58. * \brief Access exFat partitions on raw file devices.
  59. */
  60. class ExFatPartition {
  61. public:
  62. ExFatPartition() {}
  63. /** \return the number of bytes in a cluster. */
  64. uint32_t bytesPerCluster() const {return m_bytesPerCluster;}
  65. /** \return the power of two for bytesPerCluster. */
  66. uint8_t bytesPerClusterShift() const {
  67. return m_bytesPerSectorShift + m_sectorsPerClusterShift;
  68. }
  69. /** \return the number of bytes in a sector. */
  70. uint16_t bytesPerSector() const {return m_bytesPerSector;}
  71. /** \return the power of two for bytesPerSector. */
  72. uint8_t bytesPerSectorShift() const {return m_bytesPerSectorShift;}
  73. /** Clear the cache and returns a pointer to the cache. Not for normal apps.
  74. * \return A pointer to the cache buffer or zero if an error occurs.
  75. */
  76. uint8_t* cacheClear() {
  77. return m_dataCache.clear();
  78. }
  79. /** \return the cluster count for the partition. */
  80. uint32_t clusterCount() const {return m_clusterCount;}
  81. /** \return the cluster heap start sector. */
  82. uint32_t clusterHeapStartSector() const {return m_clusterHeapStartSector;}
  83. /** End access to volume
  84. * \return pointer to sector size buffer for format.
  85. */
  86. uint8_t* end() {
  87. m_fatType = 0;
  88. return cacheClear();
  89. }
  90. /** \return the FAT length in sectors */
  91. uint32_t fatLength() const {return m_fatLength;}
  92. /** \return the FAT start sector number. */
  93. uint32_t fatStartSector() const {return m_fatStartSector;}
  94. /** \return Type FAT_TYPE_EXFAT for exFAT partition or zero for error. */
  95. uint8_t fatType() const {return m_fatType;}
  96. /** \return free cluster count or -1 if an error occurs. */
  97. int32_t freeClusterCount();
  98. /** Initialize a exFAT partition.
  99. * \param[in] dev The blockDevice for the partition.
  100. * \param[in] part The partition to be used. Legal values for \a part are
  101. * 1-4 to use the corresponding partition on a device formatted with
  102. * a MBR, Master Boot Record, or zero if the device is formatted as
  103. * a super floppy with the FAT boot sector in sector volStart.
  104. * \param[in] volStart location of volume if part is zero.
  105. *
  106. * \return true for success or false for failure.
  107. */
  108. bool init(FsBlockDevice* dev, uint8_t part, uint32_t volStart = 0);
  109. /**
  110. * Check for device busy.
  111. *
  112. * \return true if busy else false.
  113. */
  114. bool isBusy() {return m_blockDev->isBusy();}
  115. /** \return the root directory start cluster number. */
  116. uint32_t rootDirectoryCluster() const {return m_rootDirectoryCluster;}
  117. /** \return the root directory length. */
  118. uint32_t rootLength();
  119. /** \return the number of sectors in a cluster. */
  120. uint32_t sectorsPerCluster() const {return 1UL << m_sectorsPerClusterShift;}
  121. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  122. uint32_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster();
  123. #endif // DOXYGEN_SHOULD_SKIP_THIS
  124. /** \return the power of two for sectors per cluster. */
  125. uint8_t sectorsPerClusterShift() const {return m_sectorsPerClusterShift;}
  126. //----------------------------------------------------------------------------
  127. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  128. void checkUpcase(print_t* pr);
  129. bool printDir(print_t* pr, ExFatFile* file);
  130. void dmpBitmap(print_t* pr);
  131. void dmpCluster(print_t* pr, uint32_t cluster,
  132. uint32_t offset, uint32_t count);
  133. void dmpFat(print_t* pr, uint32_t start, uint32_t count);
  134. void dmpSector(print_t* pr, uint32_t sector);
  135. bool printVolInfo(print_t* pr);
  136. void printFat(print_t* pr);
  137. void printUpcase(print_t* pr);
  138. #endif // DOXYGEN_SHOULD_SKIP_THIS
  139. //----------------------------------------------------------------------------
  140. private:
  141. /** ExFatFile allowed access to private members. */
  142. friend class ExFatFile;
  143. uint32_t bitmapFind(uint32_t cluster, uint32_t count);
  144. bool bitmapModify(uint32_t cluster, uint32_t count, bool value);
  145. //----------------------------------------------------------------------------
  146. // Cache functions.
  147. uint8_t* bitmapCachePrepare(uint32_t sector, uint8_t option) {
  148. #if USE_EXFAT_BITMAP_CACHE
  149. return m_bitmapCache.prepare(sector, option);
  150. #else // USE_EXFAT_BITMAP_CACHE
  151. return m_dataCache.prepare(sector, option);
  152. #endif // USE_EXFAT_BITMAP_CACHE
  153. }
  154. void cacheInit(FsBlockDevice* dev) {
  155. #if USE_EXFAT_BITMAP_CACHE
  156. m_bitmapCache.init(dev);
  157. #endif // USE_EXFAT_BITMAP_CACHE
  158. m_dataCache.init(dev);
  159. }
  160. bool cacheSync() {
  161. #if USE_EXFAT_BITMAP_CACHE
  162. return m_bitmapCache.sync() && m_dataCache.sync() && syncDevice();
  163. #else // USE_EXFAT_BITMAP_CACHE
  164. return m_dataCache.sync() && syncDevice();
  165. #endif // USE_EXFAT_BITMAP_CACHE
  166. }
  167. void dataCacheDirty() {m_dataCache.dirty();}
  168. void dataCacheInvalidate() {m_dataCache.invalidate();}
  169. uint8_t* dataCachePrepare(uint32_t sector, uint8_t option) {
  170. return m_dataCache.prepare(sector, option);
  171. }
  172. uint32_t dataCacheSector() {return m_dataCache.sector();}
  173. bool dataCacheSync() {return m_dataCache.sync();}
  174. //----------------------------------------------------------------------------
  175. uint32_t clusterMask() const {return m_clusterMask;}
  176. uint32_t clusterStartSector(uint32_t cluster) {
  177. return m_clusterHeapStartSector +
  178. ((cluster - 2) << m_sectorsPerClusterShift);
  179. }
  180. uint8_t* dirCache(DirPos_t* pos, uint8_t options);
  181. int8_t dirSeek(DirPos_t* pos, uint32_t offset);
  182. int8_t fatGet(uint32_t cluster, uint32_t* value);
  183. bool fatPut(uint32_t cluster, uint32_t value);
  184. uint32_t chainSize(uint32_t cluster);
  185. bool freeChain(uint32_t cluster);
  186. uint16_t sectorMask() const {return m_sectorMask;}
  187. bool syncDevice() {
  188. return m_blockDev->syncDevice();
  189. }
  190. bool cacheSafeRead(uint32_t sector, uint8_t* dst) {
  191. return m_dataCache.cacheSafeRead(sector, dst);
  192. }
  193. bool cacheSafeWrite(uint32_t sector, const uint8_t* src) {
  194. return m_dataCache.cacheSafeWrite(sector, src);
  195. }
  196. bool cacheSafeRead(uint32_t sector, uint8_t* dst, size_t count) {
  197. return m_dataCache.cacheSafeRead(sector, dst, count);
  198. }
  199. bool cacheSafeWrite(uint32_t sector, const uint8_t* src, size_t count) {
  200. return m_dataCache.cacheSafeWrite(sector, src, count);
  201. }
  202. bool readSector(uint32_t sector, uint8_t* dst) {
  203. return m_blockDev->readSector(sector, dst);
  204. }
  205. bool writeSector(uint32_t sector, const uint8_t* src) {
  206. return m_blockDev->writeSector(sector, src);
  207. }
  208. //----------------------------------------------------------------------------
  209. static const uint8_t m_bytesPerSectorShift = 9;
  210. static const uint16_t m_bytesPerSector = 1 << m_bytesPerSectorShift;
  211. static const uint16_t m_sectorMask = m_bytesPerSector - 1;
  212. //----------------------------------------------------------------------------
  213. #if USE_EXFAT_BITMAP_CACHE
  214. FsCache m_bitmapCache;
  215. #endif // USE_EXFAT_BITMAP_CACHE
  216. FsCache m_dataCache;
  217. uint32_t m_bitmapStart;
  218. uint32_t m_fatStartSector;
  219. uint32_t m_fatLength;
  220. uint32_t m_clusterHeapStartSector;
  221. uint32_t m_clusterCount;
  222. uint32_t m_rootDirectoryCluster;
  223. uint32_t m_clusterMask;
  224. uint32_t m_bytesPerCluster;
  225. FsBlockDevice* m_blockDev;
  226. uint8_t m_fatType = 0;
  227. uint8_t m_sectorsPerClusterShift;
  228. };
  229. #endif // ExFatPartition_h