Files
ESP8266lib/ext/sd/fat32/FS.h

120 lines
3.5 KiB
C++

#pragma once
#include <cstdint>
#include <functional>
#include "Structs.h"
// https://www.pjrc.com/tech/8051/ide/fat32.html
namespace FAT32 {
template <typename BlockDev> 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<uint8_t*>(&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);
}
};
}