ExFatPartition.h 9.0 KB

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