You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

339 lines
11KB

  1. /* FatLib Library
  2. * Copyright (C) 2013 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. #ifndef FatVolume_h
  21. #define FatVolume_h
  22. /**
  23. * \file
  24. * \brief FatVolume class
  25. */
  26. #include <stddef.h>
  27. #include "FatLibConfig.h"
  28. #include "FatStructs.h"
  29. //------------------------------------------------------------------------------
  30. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  31. /** Macro for debug. */
  32. #define DEBUG_MODE 0
  33. #if DEBUG_MODE
  34. #include <Arduino.h>
  35. #define DBG_FAIL_MACRO Serial.print(F(__FILE__)); Serial.println(__LINE__)
  36. #define DBG_PRINT_IF(b) if (b) {Serial.println(F(#b)); DBG_FAIL_MACRO;}
  37. #define DBG_HALT_IF(b) if (b) {Serial.println(F(#b));\
  38. DBG_FAIL_MACRO; while (1);}
  39. #else // DEBUG_MODE
  40. #define DBG_FAIL_MACRO
  41. #define DBG_PRINT_IF(b)
  42. #define DBG_HALT_IF(b)
  43. #endif // DEBUG_MODE
  44. #endif // DOXYGEN_SHOULD_SKIP_THIS
  45. //------------------------------------------------------------------------------
  46. #if ENABLE_ARDUINO_FEATURES
  47. #include <Arduino.h>
  48. /** Use Print on Arduino */
  49. typedef Print print_t;
  50. #else // ENABLE_ARDUINO_FEATURES
  51. // Arduino type for flash string.
  52. class __FlashStringHelper;
  53. /**
  54. * \class CharWriter
  55. * \brief Character output - often serial port.
  56. */
  57. class CharWriter {
  58. public:
  59. virtual size_t write(char c) = 0;
  60. virtual size_t write(const char* s) = 0;
  61. };
  62. typedef CharWriter print_t;
  63. #endif // ENABLE_ARDUINO_FEATURES
  64. //------------------------------------------------------------------------------
  65. // Forward declaration of FatVolume.
  66. class FatVolume;
  67. //------------------------------------------------------------------------------
  68. /**
  69. * \brief Cache for an raw data block.
  70. */
  71. union cache_t {
  72. /** Used to access cached file data blocks. */
  73. uint8_t data[512];
  74. /** Used to access cached FAT16 entries. */
  75. uint16_t fat16[256];
  76. /** Used to access cached FAT32 entries. */
  77. uint32_t fat32[128];
  78. /** Used to access cached directory entries. */
  79. dir_t dir[16];
  80. /** Used to access a cached Master Boot Record. */
  81. mbr_t mbr;
  82. /** Used to access to a cached FAT boot sector. */
  83. fat_boot_t fbs;
  84. /** Used to access to a cached FAT32 boot sector. */
  85. fat32_boot_t fbs32;
  86. /** Used to access to a cached FAT32 FSINFO sector. */
  87. fat32_fsinfo_t fsinfo;
  88. };
  89. //==============================================================================
  90. /**
  91. * \class FatCache
  92. * \brief Block cache.
  93. */
  94. class FatCache {
  95. public:
  96. /** Cached block is dirty */
  97. static const uint8_t CACHE_STATUS_DIRTY = 1;
  98. /** Cashed block is FAT entry and must be mirrored in second FAT. */
  99. static const uint8_t CACHE_STATUS_MIRROR_FAT = 2;
  100. /** Cache block status bits */
  101. static const uint8_t CACHE_STATUS_MASK
  102. = CACHE_STATUS_DIRTY | CACHE_STATUS_MIRROR_FAT;
  103. /** Sync existing block but do not read new block. */
  104. static const uint8_t CACHE_OPTION_NO_READ = 4;
  105. /** Cache block for read. */
  106. static uint8_t const CACHE_FOR_READ = 0;
  107. /** Cache block for write. */
  108. static uint8_t const CACHE_FOR_WRITE = CACHE_STATUS_DIRTY;
  109. /** Reserve cache block for write - do not read from block device. */
  110. static uint8_t const CACHE_RESERVE_FOR_WRITE
  111. = CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ;
  112. /** \return Cache block address. */
  113. cache_t* block() {
  114. return &m_block;
  115. }
  116. /** Set current block dirty. */
  117. void dirty() {
  118. m_status |= CACHE_STATUS_DIRTY;
  119. }
  120. /** Initialize the cache.
  121. * \param[in] vol FatVolume that owns this FatCache.
  122. */
  123. void init(FatVolume *vol) {
  124. m_vol = vol;
  125. invalidate();
  126. }
  127. /** Invalidate current cache block. */
  128. void invalidate() {
  129. m_status = 0;
  130. m_lbn = 0XFFFFFFFF;
  131. }
  132. /** \return Logical block number for cached block. */
  133. uint32_t lbn() {
  134. return m_lbn;
  135. }
  136. /** Read a block into the cache.
  137. * \param[in] lbn Block to read.
  138. * \param[in] option mode for cached block.
  139. * \return Address of cached block. */
  140. cache_t* read(uint32_t lbn, uint8_t option);
  141. /** Write current block if dirty.
  142. * \return true for success else false.
  143. */
  144. bool sync();
  145. private:
  146. uint8_t m_status;
  147. FatVolume* m_vol;
  148. uint32_t m_lbn;
  149. cache_t m_block;
  150. };
  151. //==============================================================================
  152. /**
  153. * \class FatVolume
  154. * \brief Access FAT16 and FAT32 volumes on raw file devices.
  155. */
  156. class FatVolume {
  157. public:
  158. /** Create an instance of FatVolume
  159. */
  160. FatVolume() : m_fatType(0) {}
  161. /** \return The volume's cluster size in blocks. */
  162. uint8_t blocksPerCluster() const {
  163. return m_blocksPerCluster;
  164. }
  165. /** \return The number of blocks in one FAT. */
  166. uint32_t blocksPerFat() const {
  167. return m_blocksPerFat;
  168. }
  169. /** Clear the cache and returns a pointer to the cache. Not for normal apps.
  170. * \return A pointer to the cache buffer or zero if an error occurs.
  171. */
  172. cache_t* cacheClear() {
  173. if (!cacheSync()) {
  174. return 0;
  175. }
  176. m_cache.invalidate();
  177. return m_cache.block();
  178. }
  179. /** \return The total number of clusters in the volume. */
  180. uint32_t clusterCount() const {
  181. return m_lastCluster - 1;
  182. }
  183. /** \return The shift count required to multiply by blocksPerCluster. */
  184. uint8_t clusterSizeShift() const {
  185. return m_clusterSizeShift;
  186. }
  187. /** \return The logical block number for the start of file data. */
  188. uint32_t dataStartBlock() const {
  189. return m_dataStartBlock;
  190. }
  191. /** \return The number of File Allocation Tables. */
  192. uint8_t fatCount() {
  193. return 2;
  194. }
  195. /** \return The logical block number for the start of the first FAT. */
  196. uint32_t fatStartBlock() const {
  197. return m_fatStartBlock;
  198. }
  199. /** \return The FAT type of the volume. Values are 12, 16 or 32. */
  200. uint8_t fatType() const {
  201. return m_fatType;
  202. }
  203. /** Volume free space in clusters.
  204. *
  205. * \return Count of free clusters for success or -1 if an error occurs.
  206. */
  207. int32_t freeClusterCount();
  208. /** Initialize a FAT volume. Try partition one first then try super
  209. * floppy format.
  210. *
  211. * \return The value true is returned for success and
  212. * the value false is returned for failure.
  213. */
  214. bool init() {
  215. return init(1) || init(0);
  216. }
  217. /** Initialize a FAT volume.
  218. * \param[in] part The partition to be used. Legal values for \a part are
  219. * 1-4 to use the corresponding partition on a device formatted with
  220. * a MBR, Master Boot Record, or zero if the device is formatted as
  221. * a super floppy with the FAT boot sector in block zero.
  222. *
  223. * \return The value true is returned for success and
  224. * the value false is returned for failure.
  225. */
  226. bool init(uint8_t part);
  227. /** \return The number of entries in the root directory for FAT16 volumes. */
  228. uint16_t rootDirEntryCount() const {
  229. return m_rootDirEntryCount;
  230. }
  231. /** \return The logical block number for the start of the root directory
  232. on FAT16 volumes or the first cluster number on FAT32 volumes. */
  233. uint32_t rootDirStart() const {
  234. return m_rootDirStart;
  235. }
  236. /** \return The number of blocks in the volume */
  237. uint32_t volumeBlockCount() const {
  238. return blocksPerCluster()*clusterCount();
  239. }
  240. /** Wipe all data from the volume.
  241. * \param[in] pr print stream for status dots.
  242. * \return true for success else false.
  243. */
  244. bool wipe(print_t* pr = 0);
  245. /** Debug access to FAT table
  246. *
  247. * \param[in] n cluster number.
  248. * \param[out] v value of entry
  249. * \return true for success or false for failure
  250. */
  251. int8_t dbgFat(uint32_t n, uint32_t* v) {
  252. return fatGet(n, v);
  253. }
  254. //------------------------------------------------------------------------------
  255. private:
  256. // Allow FatFile and FatCache access to FatVolume private functions.
  257. friend class FatCache;
  258. friend class FatFile;
  259. //------------------------------------------------------------------------------
  260. uint8_t m_blocksPerCluster; // Cluster size in blocks.
  261. uint8_t m_clusterBlockMask; // Mask to extract block of cluster.
  262. uint8_t m_clusterSizeShift; // Cluster count to block count shift.
  263. uint8_t m_fatType; // Volume type (12, 16, OR 32).
  264. uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
  265. uint32_t m_allocSearchStart; // Start cluster for alloc search.
  266. uint32_t m_blocksPerFat; // FAT size in blocks
  267. uint32_t m_dataStartBlock; // First data block number.
  268. uint32_t m_fatStartBlock; // Start block for first FAT.
  269. uint32_t m_lastCluster; // Last cluster number in FAT.
  270. uint32_t m_rootDirStart; // Start block for FAT16, cluster for FAT32.
  271. //------------------------------------------------------------------------------
  272. // block caches
  273. FatCache m_cache;
  274. #if USE_SEPARATE_FAT_CACHE
  275. FatCache m_fatCache;
  276. cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options) {
  277. return m_fatCache.read(blockNumber,
  278. options | FatCache::CACHE_STATUS_MIRROR_FAT);
  279. }
  280. bool cacheSync() {
  281. return m_cache.sync() && m_fatCache.sync();
  282. }
  283. #else //
  284. cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options) {
  285. return cacheFetchData(blockNumber,
  286. options | FatCache::CACHE_STATUS_MIRROR_FAT);
  287. }
  288. bool cacheSync() {
  289. return m_cache.sync();
  290. }
  291. #endif // USE_SEPARATE_FAT_CACHE
  292. cache_t* cacheFetchData(uint32_t blockNumber, uint8_t options) {
  293. return m_cache.read(blockNumber, options);
  294. }
  295. void cacheInvalidate() {
  296. m_cache.invalidate();
  297. }
  298. bool cacheSyncData() {
  299. return m_cache.sync();
  300. }
  301. cache_t *cacheAddress() {
  302. return m_cache.block();
  303. }
  304. uint32_t cacheBlockNumber() {
  305. return m_cache.lbn();
  306. }
  307. void cacheDirty() {
  308. m_cache.dirty();
  309. }
  310. //------------------------------------------------------------------------------
  311. bool allocateCluster(uint32_t current, uint32_t* next);
  312. bool allocContiguous(uint32_t count, uint32_t* firstCluster);
  313. uint8_t blockOfCluster(uint32_t position) const {
  314. return (position >> 9) & m_clusterBlockMask;
  315. }
  316. uint32_t clusterStartBlock(uint32_t cluster) const;
  317. int8_t fatGet(uint32_t cluster, uint32_t* value);
  318. bool fatPut(uint32_t cluster, uint32_t value);
  319. bool fatPutEOC(uint32_t cluster) {
  320. return fatPut(cluster, 0x0FFFFFFF);
  321. }
  322. bool freeChain(uint32_t cluster);
  323. bool isEOC(uint32_t cluster) const {
  324. return cluster > m_lastCluster;
  325. }
  326. //----------------------------------------------------------------------------
  327. // Virtual block I/O functions.
  328. virtual bool readBlock(uint32_t block, uint8_t* dst) = 0;
  329. virtual bool writeBlock(uint32_t block, const uint8_t* src) = 0;
  330. #if USE_MULTI_BLOCK_IO
  331. virtual bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) = 0;
  332. virtual bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) = 0;
  333. #endif // USE_MULTI_BLOCK_IO
  334. };
  335. #endif // FatVolume