123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /**
- * Copyright (c) 2011-2020 Bill Greiman
- * This file is part of the SdFat library for SD memory cards.
- *
- * MIT License
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- #ifndef FatPartition_h
- #define FatPartition_h
- /**
- * \file
- * \brief FatPartition class
- */
- #include <stddef.h>
- #include "FatLibConfig.h"
- #include "../common/SysCall.h"
- #include "../common/BlockDevice.h"
- #include "../common/FsStructs.h"
- /** Type for FAT12 partition */
- const uint8_t FAT_TYPE_FAT12 = 12;
- /** Type for FAT12 partition */
- const uint8_t FAT_TYPE_FAT16 = 16;
- /** Type for FAT12 partition */
- const uint8_t FAT_TYPE_FAT32 = 32;
- //------------------------------------------------------------------------------
- // Forward declaration of FatPartition.
- class FatPartition;
- //------------------------------------------------------------------------------
- /**
- * \brief Cache for an raw data sector.
- */
- union cache_t {
- /** Used to access cached file data sectors. */
- uint8_t data[512];
- /** Used to access cached FAT16 entries. */
- uint16_t fat16[256];
- /** Used to access cached FAT32 entries. */
- uint32_t fat32[128];
- /** Used to access cached directory entries. */
- DirFat_t dir[16];
- };
- //==============================================================================
- /**
- * \class FatCache
- * \brief Sector cache.
- */
- class FatCache {
- public:
- /** Cached sector is dirty */
- static const uint8_t CACHE_STATUS_DIRTY = 1;
- /** Cashed sector is FAT entry and must be mirrored in second FAT. */
- static const uint8_t CACHE_STATUS_MIRROR_FAT = 2;
- /** Cache sector status bits */
- static const uint8_t CACHE_STATUS_MASK
- = CACHE_STATUS_DIRTY | CACHE_STATUS_MIRROR_FAT;
- /** Sync existing sector but do not read new sector. */
- static const uint8_t CACHE_OPTION_NO_READ = 4;
- /** Cache sector for read. */
- static const uint8_t CACHE_FOR_READ = 0;
- /** Cache sector for write. */
- static const uint8_t CACHE_FOR_WRITE = CACHE_STATUS_DIRTY;
- /** Reserve cache sector for write - do not read from sector device. */
- static const uint8_t CACHE_RESERVE_FOR_WRITE
- = CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ;
- /** \return Cache sector address. */
- cache_t* buffer() {
- return &m_buffer;
- }
- /** Set current sector dirty. */
- void dirty() {
- m_status |= CACHE_STATUS_DIRTY;
- }
- /** Initialize the cache.
- * \param[in] vol FatPartition that owns this FatCache.
- */
- void init(FatPartition *vol) {
- m_part = vol;
- invalidate();
- }
- /** Invalidate current cache sector. */
- void invalidate() {
- m_status = 0;
- m_lbn = 0XFFFFFFFF;
- }
- /** \return dirty status */
- bool isDirty() {
- return m_status & CACHE_STATUS_DIRTY;
- }
- /** \return Logical sector number for cached sector. */
- uint32_t sector() {
- return m_lbn;
- }
- /** Read a sector into the cache.
- * \param[in] sector Sector to read.
- * \param[in] option mode for cached sector.
- * \return Address of cached sector. */
- cache_t* read(uint32_t sector, uint8_t option);
- /** Write current sector if dirty.
- * \return true for success or false for failure.
- */
- bool sync();
- private:
- uint8_t m_status;
- FatPartition* m_part;
- uint32_t m_lbn;
- cache_t m_buffer;
- };
- //==============================================================================
- /**
- * \class FatPartition
- * \brief Access FAT16 and FAT32 partitions on raw file devices.
- */
- class FatPartition {
- public:
- /** Create an instance of FatPartition
- */
- FatPartition() : m_fatType(0) {}
- /** \return The shift count required to multiply by bytesPerCluster. */
- uint8_t bytesPerClusterShift() {
- return m_sectorsPerClusterShift + m_bytesPerSectorShift;
- }
- /** \return Number of bytes in a cluster. */
- uint16_t bytesPerCluster() {
- return m_bytesPerSector << m_sectorsPerClusterShift;
- }
- /** \return Number of bytes per sector. */
- uint16_t bytesPerSector() {
- return m_bytesPerSector;
- }
- /** \return The shift count required to multiply by bytesPerCluster. */
- uint8_t bytesPerSectorShift() {
- return m_bytesPerSectorShift;
- }
- /** \return Mask for sector offset. */
- uint16_t sectorMask() {
- return m_sectorMask;
- }
- /** \return The volume's cluster size in sectors. */
- uint8_t sectorsPerCluster() const {
- return m_sectorsPerCluster;
- }
- #ifndef DOXYGEN_SHOULD_SKIP_THIS
- // Use sectorsPerCluster(). blocksPerCluster() will be removed in the future.
- uint8_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT
- #endif // DOXYGEN_SHOULD_SKIP_THIS
- /** \return The number of sectors in one FAT. */
- uint32_t sectorsPerFat() const {
- return m_sectorsPerFat;
- }
- /** Clear the cache and returns a pointer to the cache. Not for normal apps.
- * \return A pointer to the cache buffer or zero if an error occurs.
- */
- cache_t* cacheClear() {
- if (!cacheSync()) {
- return nullptr;
- }
- m_cache.invalidate();
- return m_cache.buffer();
- }
- /** \return The total number of clusters in the volume. */
- uint32_t clusterCount() const {
- return m_lastCluster - 1;
- }
- /** \return The shift count required to multiply by sectorsPerCluster. */
- uint8_t sectorsPerClusterShift() const {
- return m_sectorsPerClusterShift;
- }
- /** \return The logical sector number for the start of file data. */
- uint32_t dataStartSector() const {
- return m_dataStartSector;
- }
- /** \return The number of File Allocation Tables. */
- uint8_t fatCount() {
- return 2;
- }
- /** \return The logical sector number for the start of the first FAT. */
- uint32_t fatStartSector() const {
- return m_fatStartSector;
- }
- /** \return The FAT type of the volume. Values are 12, 16 or 32. */
- uint8_t fatType() const {
- return m_fatType;
- }
- /** Volume free space in clusters.
- *
- * \return Count of free clusters for success or -1 if an error occurs.
- */
- int32_t freeClusterCount();
- /** Initialize a FAT partition.
- *
- * \param[in] dev BlockDevice for this partition.
- * \param[in] part The partition to be used. Legal values for \a part are
- * 1-4 to use the corresponding partition on a device formatted with
- * a MBR, Master Boot Record, or zero if the device is formatted as
- * a super floppy with the FAT boot sector in sector zero.
- *
- * \return true for success or false for failure.
- */
- bool init(BlockDevice* dev, uint8_t part = 1);
- /** \return The number of entries in the root directory for FAT16 volumes. */
- uint16_t rootDirEntryCount() const {
- return m_rootDirEntryCount;
- }
- /** \return The logical sector number for the start of the root directory
- on FAT16 volumes or the first cluster number on FAT32 volumes. */
- uint32_t rootDirStart() const {
- return m_rootDirStart;
- }
- /** \return The number of sectors in the volume */
- uint32_t volumeSectorCount() const {
- return sectorsPerCluster()*clusterCount();
- }
- /** Debug access to FAT table
- *
- * \param[in] n cluster number.
- * \param[out] v value of entry
- * \return -1 error, 0 EOC, else 1.
- */
- int8_t dbgFat(uint32_t n, uint32_t* v) {
- return fatGet(n, v);
- }
- //----------------------------------------------------------------------------
- #ifndef DOXYGEN_SHOULD_SKIP_THIS
- void dmpDirSector(print_t* pr, uint32_t sector);
- void dmpFat(print_t* pr, uint32_t start, uint32_t count);
- void dmpRootDir(print_t* pr);
- void dmpSector(print_t* pr, uint32_t sector, uint8_t bits = 8);
- #endif // DOXYGEN_SHOULD_SKIP_THIS
- //----------------------------------------------------------------------------
- private:
- /** FatCache allowed access to private members. */
- friend class FatCache;
- /** FatFile allowed access to private members. */
- friend class FatFile;
- //----------------------------------------------------------------------------
- static const uint8_t m_bytesPerSectorShift = 9;
- static const uint16_t m_bytesPerSector = 512;
- static const uint16_t m_sectorMask = 0x1FF;
- //----------------------------------------------------------------------------
- BlockDevice* m_blockDev; // sector device
- uint8_t m_sectorsPerCluster; // Cluster size in sectors.
- uint8_t m_clusterSectorMask; // Mask to extract sector of cluster.
- uint8_t m_sectorsPerClusterShift; // Cluster count to sector count shift.
- uint8_t m_fatType; // Volume type (12, 16, OR 32).
- uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
- uint32_t m_allocSearchStart; // Start cluster for alloc search.
- uint32_t m_sectorsPerFat; // FAT size in sectors
- uint32_t m_dataStartSector; // First data sector number.
- uint32_t m_fatStartSector; // Start sector for first FAT.
- uint32_t m_lastCluster; // Last cluster number in FAT.
- uint32_t m_rootDirStart; // Start sector FAT16, cluster FAT32.
- //----------------------------------------------------------------------------
- // sector I/O functions.
- bool readSector(uint32_t sector, uint8_t* dst) {
- return m_blockDev->readSector(sector, dst);
- }
- bool syncDevice() {
- return m_blockDev->syncDevice();
- }
- bool writeSector(uint32_t sector, const uint8_t* src) {
- return m_blockDev->writeSector(sector, src);
- }
- #if USE_MULTI_SECTOR_IO
- bool readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
- return m_blockDev->readSectors(sector, dst, ns);
- }
- bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns) {
- return m_blockDev->writeSectors(sector, src, ns);
- }
- #endif // USE_MULTI_SECTOR_IO
- #if MAINTAIN_FREE_CLUSTER_COUNT
- int32_t m_freeClusterCount; // Count of free clusters in volume.
- void setFreeClusterCount(int32_t value) {
- m_freeClusterCount = value;
- }
- void updateFreeClusterCount(int32_t change) {
- if (m_freeClusterCount >= 0) {
- m_freeClusterCount += change;
- }
- }
- #else // MAINTAIN_FREE_CLUSTER_COUNT
- void setFreeClusterCount(int32_t value) {
- (void)value;
- }
- void updateFreeClusterCount(int32_t change) {
- (void)change;
- }
- #endif // MAINTAIN_FREE_CLUSTER_COUNT
- // sector caches
- FatCache m_cache;
- #if USE_SEPARATE_FAT_CACHE
- FatCache m_fatCache;
- cache_t* cacheFetchFat(uint32_t sector, uint8_t options) {
- return m_fatCache.read(sector,
- options | FatCache::CACHE_STATUS_MIRROR_FAT);
- }
- bool cacheSync() {
- return m_cache.sync() && m_fatCache.sync() && syncDevice();
- }
- #else // USE_SEPARATE_FAT_CACHE
- cache_t* cacheFetchFat(uint32_t sector, uint8_t options) {
- return cacheFetchData(sector,
- options | FatCache::CACHE_STATUS_MIRROR_FAT);
- }
- bool cacheSync() {
- return m_cache.sync() && syncDevice();
- }
- #endif // USE_SEPARATE_FAT_CACHE
- cache_t* cacheFetchData(uint32_t sector, uint8_t options) {
- return m_cache.read(sector, options);
- }
- void cacheInvalidate() {
- m_cache.invalidate();
- }
- bool cacheSyncData() {
- return m_cache.sync();
- }
- cache_t* cacheAddress() {
- return m_cache.buffer();
- }
- uint32_t cacheSectorNumber() {
- return m_cache.sector();
- }
- void cacheDirty() {
- m_cache.dirty();
- }
- //----------------------------------------------------------------------------
- bool allocateCluster(uint32_t current, uint32_t* next);
- bool allocContiguous(uint32_t count, uint32_t* firstCluster);
- uint8_t sectorOfCluster(uint32_t position) const {
- return (position >> 9) & m_clusterSectorMask;
- }
- uint32_t clusterStartSector(uint32_t cluster) const;
- int8_t fatGet(uint32_t cluster, uint32_t* value);
- bool fatPut(uint32_t cluster, uint32_t value);
- bool fatPutEOC(uint32_t cluster) {
- return fatPut(cluster, 0x0FFFFFFF);
- }
- bool freeChain(uint32_t cluster);
- bool isEOC(uint32_t cluster) const {
- return cluster > m_lastCluster;
- }
- };
- #endif // FatPartition
|