#pragma once #include #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" #include "WriteFile.h" #include "FreeClusterIterator.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.size, de.getFirstCluster()); } // /** create a new file for writing, in the given directory */ // WriteFile newFile(DirEntry& de, const uint32_t size) { // if (!de.isDirectory()) {return nullptr;} // uint32_t allocSize = 0; // FreeClusterIterator fci(*this); // while(allocSize < size) { // ClusterNr = fci.next(); // } // } private: void init() { Log::addInfo(NAME, "init @ %d", offset); 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); Log::addInfo(NAME, "Bytes/Sector: %d, Sector/Cluster: %d, FATs: %d, RootDir: %d", desc.bytesPerSector, desc.sectorsPerCluster, desc.numberOfFATs, desc.rootDirFirstCluster); /* 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 = 0; dev.read(pos, 4, reinterpret_cast(&next)); Log::addInfo(NAME, "nextCluster(%d) -> %d", clusterNr, next); return next; } /** convert ClusterNr into an absolute position on disk */ AbsPos clusterToAbsPos(ClusterNr clusterNr) { return tmp.startOfFirstDataCluster + ((clusterNr - 2) * desc.sectorsPerCluster * desc.bytesPerSector); } }; }