#pragma once #include #include "Structs.h" // https://www.pjrc.com/tech/8051/ide/fat32.html namespace FAT32 { template class FS { static constexpr const char* NAME = "FAT32"; BlockDev& dev; AbsOffset offset; FSDesc desc; Precomputed tmp; bool valid = false; public: #include "File.h" #include "DirIterator.h" /** ctor with the absolute offset addr (in bytes) */ FS(BlockDev& dev, AbsOffset offset) : dev(dev), offset(offset) { init(); } /** is the detected FS valid? */ bool isValid() const { return valid; } /** get an iterator for the root directory */ DirIterator getRoot() { return DirIterator(*this, desc.rootDirFirstCluster); } /** open the given file for reading*/ File open(const DirEntry& de) { return File(*this, de.getFirstCluster(), de.size); } private: void init() { debugMod3(NAME") uint8_t buf[512]; dev.read(offset, 512, buf); desc.bytesPerSector = getU16(&buf[0x0B]); desc.sectorsPerCluster = getU8(&buf[0x0D]); desc.numReservedSectors = getU16(&buf[0x0E]); desc.numberOfFATs = getU8(&buf[0x10]); desc.sectorsPerFAT = getU32(&buf[0x24]); desc.rootDirFirstCluster = getU32(&buf[0x2C]); // basic sanity check based on constants valid = (desc.bytesPerSector == 512) && (desc.numberOfFATs == 2) && (getU16(&buf[0x1FE]) == 0xAA55); tmp.bytesPerCluster = desc.sectorsPerCluster * desc.bytesPerSector; tmp.startOfFAT = offset + (desc.numReservedSectors * desc.bytesPerSector); tmp.startOfFirstDataCluster = offset + (desc.numReservedSectors * desc.bytesPerSector) + (desc.numberOfFATs * desc.sectorsPerFAT * desc.bytesPerSector); tmp.startOfFirstRootDirCluster = clusterToAbsPos(desc.rootDirFirstCluster); tmp.dirEntriesPerSector = desc.bytesPerSector / sizeof(DirEntry); /* std::cout << (int)desc.bytesPerSector << std::endl; std::cout << (int)desc.sectorsPerCluster << std::endl; std::cout << (int)desc.numReservedSectors << std::endl; std::cout << (int)desc.numberOfFATs << std::endl; std::cout << (int)desc.sectorsPerFAT << std::endl; std::cout << (int)desc.rootDirFirstCluster << std::endl; std::cout << tmp.startOfFAT << std::endl; std::cout << tmp.startOfFirstDataCluster << std::endl; std::cout << tmp.startOfFirstRootDirCluster << std::endl; */ } /** determine the ClusterNr following the given ClusterNr */ ClusterNr getNextCluster(ClusterNr clusterNr) { const AbsPos pos = tmp.startOfFAT + ((clusterNr) * sizeof(uint32_t)); ClusterNr next; int read = dev.read(pos, 4, reinterpret_cast(&next)); return next; } /** convert ClusterNr into an absolute position on disk */ AbsPos clusterToAbsPos(ClusterNr clusterNr) { return tmp.startOfFirstDataCluster + ((clusterNr - 2) * desc.sectorsPerCluster * desc.bytesPerSector); } }; }