worked on FAT stuff and tests
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Structs.h"
|
||||
#include "DirHandle.h"
|
||||
|
||||
// https://www.pjrc.com/tech/8051/ide/fat32.html
|
||||
namespace FAT32 {
|
||||
@@ -23,41 +24,68 @@ namespace FAT32 {
|
||||
#include "FreeClusterIterator.h"
|
||||
FreeClusterIterator fci;
|
||||
|
||||
#include "UsedSpaceChecker.h"
|
||||
|
||||
public:
|
||||
|
||||
#include "File.h"
|
||||
#include "File2.h"
|
||||
#include "DirIterator.h"
|
||||
|
||||
|
||||
#include "DirHelper.h"
|
||||
|
||||
/** ctor with the absolute offset addr (in bytes) */
|
||||
FS(BlockDev& dev, AbsOffset offset) : dev(dev), offset(offset), fci(*this) {
|
||||
init();
|
||||
}
|
||||
|
||||
void setup(uint32_t totalSize) {
|
||||
/**
|
||||
* setup a new filesystem with the given parameters
|
||||
* killFAT = zero both file allocation tables (reset all cluster numbers)
|
||||
*/
|
||||
void setup(uint32_t totalSize, const bool killFAT) {
|
||||
|
||||
uint8_t buf[512] = {0};
|
||||
buf[0x1FE] = 0x55;
|
||||
buf[0x1FF] = 0xAA;
|
||||
|
||||
FSHeader* header = (FSHeader*) buf;
|
||||
header->bytesPerSector = 512;
|
||||
header->numberOfFATs = 2;
|
||||
header->numReservedSectors = 32;
|
||||
header->rootDirFirstCluster = 2;
|
||||
header->mediaDescriptor = 0xF8; // hard disk
|
||||
header->sectorsInPartition = totalSize / 512;
|
||||
header->sectorsPerCluster = 8;
|
||||
header->sectorsPerFAT = 64; // 8 MB
|
||||
const uint32_t sectorsPerCluster = 8;
|
||||
const uint32_t sizePerCluster = 512 * sectorsPerCluster;
|
||||
const uint32_t sectorsPerFAT = totalSize / sizePerCluster * sizeof(ClusterNr) / 512;
|
||||
|
||||
FSHeader* header = (FSHeader*) buf;
|
||||
header->bytesPerSector = 512; // always
|
||||
header->numberOfFATs = 2; // always
|
||||
header->numReservedSectors = 32; // always
|
||||
header->rootDirFirstCluster = 2; // always
|
||||
header->mediaDescriptor = 0xF8; // hard disk
|
||||
header->sectorsInPartition = totalSize / 512;
|
||||
header->sectorsPerCluster = sectorsPerCluster; // 4096 byte clusters
|
||||
header->sectorsPerFAT = sectorsPerFAT;
|
||||
|
||||
// write the header to the underlying device
|
||||
dev.write(offset, 512, (const uint8_t*)header);
|
||||
|
||||
// now update the internal state based on the newly created FS header...
|
||||
init();
|
||||
|
||||
// mark the root-dir cluster as used
|
||||
setNextCluster(2, END_OF_CLUSTERS);
|
||||
if (killFAT) {
|
||||
|
||||
// zero-out FAT1
|
||||
uint8_t zeros[512] = {0};
|
||||
AbsPos pos = tmp.startOfFAT1;
|
||||
for (uint32_t i = 0; i < header->sectorsPerFAT; ++i) {
|
||||
dev.write(pos + i * 512, 512, zeros);
|
||||
}
|
||||
|
||||
// ...and mark the root-dir cluster as used
|
||||
setNextCluster(2, END_OF_CLUSTERS);
|
||||
|
||||
// set the first entry within the root-dir to denote the end-of-the-root-dir (no entries at all)
|
||||
DirIterator di = getRoot();
|
||||
DirHandle dh = di.next();
|
||||
dh.setEndOfDirectory();
|
||||
write(dh);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,34 +94,64 @@ namespace FAT32 {
|
||||
return valid;
|
||||
}
|
||||
|
||||
/** get the total size of the filesystem (including FATs etc.) */
|
||||
uint32_t getSize() const {
|
||||
return desc.sectorsPerFAT * desc.bytesPerSector / sizeof(ClusterNr) * tmp.bytesPerCluster;
|
||||
}
|
||||
|
||||
/** get the size that is actually usable for data (total size - required overhead) */
|
||||
uint32_t getSizeForData() const {
|
||||
return getSize() - (desc.numReservedSectors * desc.bytesPerSector) - (desc.numberOfFATs * desc.sectorsPerFAT * desc.bytesPerSector);
|
||||
}
|
||||
|
||||
/** get the number of used data bytes */
|
||||
uint32_t getSizeUsed() const {
|
||||
return UsedSpaceChecker::getNumUsedClusters(*this) * tmp.bytesPerCluster;
|
||||
}
|
||||
|
||||
/** get an iterator for the root directory */
|
||||
DirIterator getRoot() {
|
||||
return DirIterator(*this, desc.rootDirFirstCluster);
|
||||
return DirIterator(*this, 2);
|
||||
}
|
||||
|
||||
/** open the given file for reading*/
|
||||
File open(const DirEntryAt& dea) {
|
||||
return File(*this, dea.getSize(), dea.getFirstCluster());
|
||||
/** open the given file */
|
||||
File open(const DirHandle& h) {
|
||||
return File(*this, h);
|
||||
}
|
||||
|
||||
/** open the given file for reading */
|
||||
File2 open2(const DirEntryAt& dea) {
|
||||
return File2(*this, dea);
|
||||
/** create the given absolute folder */
|
||||
DirHandle mkdirs(const char* absName) {
|
||||
DirHandle h = DirHelper::getOrCreate(*this, 2, absName, DirHelper::CreateType::DIR);
|
||||
return h;
|
||||
}
|
||||
|
||||
/** get the entry with the given name */
|
||||
DirHandle getHandle(const char* absName) {
|
||||
std::string tmp(absName);
|
||||
if (tmp == "/" || tmp == "") {
|
||||
DirEntry dummy;
|
||||
DirHandle dh(0, &dummy);
|
||||
dh.setFirstCluster(desc.rootDirFirstCluster);
|
||||
return dh;
|
||||
} else {
|
||||
DirHandle h = DirHelper::getOrCreate(*this, 2, absName, DirHelper::CreateType::NONE);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
/** get or create a file with the given name */
|
||||
File2 getOrCreateFile(const char* name) {
|
||||
File getOrCreateFile(const char* absName) {
|
||||
|
||||
DirEntryAt dea = getDirEntry(name, true);
|
||||
DirHandle h = DirHelper::getOrCreate(*this, 2, absName, DirHelper::CreateType::FILE);
|
||||
|
||||
// new file -> allocate the first cluster
|
||||
if (dea.getFirstCluster() == 0) {
|
||||
if (h.getFirstCluster() == 0) {
|
||||
ClusterNr firstCluster = allocFreeCluster(0);
|
||||
dea.setFirstCluster(firstCluster);
|
||||
write(dea);
|
||||
h.setFirstCluster(firstCluster);
|
||||
write(h);
|
||||
}
|
||||
|
||||
return File2(*this, dea);
|
||||
return File(*this, h);
|
||||
|
||||
}
|
||||
|
||||
@@ -117,49 +175,20 @@ namespace FAT32 {
|
||||
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.startOfFAT1 = offset + (desc.numReservedSectors * desc.bytesPerSector);
|
||||
tmp.startOfFAT2 = tmp.startOfFAT1 + desc.sectorsPerFAT * desc.bytesPerSector;
|
||||
tmp.startOfFirstDataCluster = offset + (desc.numReservedSectors * desc.bytesPerSector) + (desc.numberOfFATs * desc.sectorsPerFAT * desc.bytesPerSector);
|
||||
tmp.startOfFirstRootDirCluster = clusterToAbsPos(desc.rootDirFirstCluster);
|
||||
tmp.entriesPerFAT = desc.sectorsPerFAT * desc.bytesPerSector / sizeof(ClusterNr);
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
/** get (or create, if needed) a DirEntry with the given name */
|
||||
DirEntryAt getDirEntry(const char* name, bool createIfNeeded) {
|
||||
|
||||
// TODO: support for sub folders)
|
||||
|
||||
// start at the root folder
|
||||
ClusterNr dirStartCluster = 2;
|
||||
|
||||
{ // search for a matching existing entry
|
||||
DirIterator di(*this, dirStartCluster);
|
||||
while(true) {
|
||||
DirEntryAt dea = di.nextUsable();
|
||||
if (!dea.isValid()) {break;}
|
||||
if (dea.getName() == name) {return dea;}
|
||||
}
|
||||
}
|
||||
|
||||
// no matching entry found
|
||||
if (!createIfNeeded) {return DirEntryAt::invalid();}
|
||||
|
||||
{ // allocate a new DirEntry for the file
|
||||
DirIterator di(*this, dirStartCluster);
|
||||
DirEntryAt dea = di.nextFree();
|
||||
dea.setName(name);
|
||||
dea.setSize(0);
|
||||
dea.setFirstCluster(0);
|
||||
return dea;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** determine the ClusterNr following the given ClusterNr */
|
||||
ClusterNr getNextCluster(const ClusterNr clusterNr) {
|
||||
const AbsPos pos = tmp.startOfFAT + (clusterNr * sizeof(ClusterNr));
|
||||
ClusterNr getNextCluster(const ClusterNr clusterNr) const {
|
||||
const AbsPos pos = tmp.startOfFAT1 + (clusterNr * sizeof(ClusterNr));
|
||||
ClusterNr next = 0;
|
||||
dev.read(pos, sizeof(ClusterNr), reinterpret_cast<uint8_t*>(&next));
|
||||
Log::addInfo(NAME, "getNextCluster(%d) -> %d", clusterNr, next);
|
||||
@@ -168,8 +197,8 @@ namespace FAT32 {
|
||||
|
||||
/** set the ClusterNr following clusterNr */
|
||||
void setNextCluster(const ClusterNr clusterNr, const ClusterNr next) {
|
||||
const AbsPos pos = tmp.startOfFAT + (clusterNr * sizeof(ClusterNr));
|
||||
dev.write(pos, sizeof(ClusterNr), reinterpret_cast<const uint8_t*>(&next));
|
||||
const AbsPos pos = tmp.startOfFAT1 + (clusterNr * sizeof(ClusterNr));
|
||||
dev.write(pos, sizeof(ClusterNr), reinterpret_cast<const uint8_t*>(&next.val));
|
||||
Log::addInfo(NAME, "setNextCluster(%d) -> %d", clusterNr, next);
|
||||
}
|
||||
|
||||
@@ -188,9 +217,18 @@ namespace FAT32 {
|
||||
return newCluster;
|
||||
}
|
||||
|
||||
/** write the given DirEntry back to disk */
|
||||
void write(const DirEntryAt& dea) {
|
||||
dev.write(dea.posOnDisk, sizeof(DirEntry), (const uint8_t*)&dea.entry);
|
||||
/** write all zeros to the given cluster */
|
||||
void zeroOutCluster(ClusterNr nr) {
|
||||
uint8_t zeros[512] = {0};
|
||||
AbsPos pos = clusterToAbsPos(nr);
|
||||
for (uint8_t i = 0; i < desc.sectorsPerCluster; ++i) {
|
||||
dev.write(pos + i * 512, 512, zeros);
|
||||
}
|
||||
}
|
||||
|
||||
/** write the given DirHandle back to disk */
|
||||
void write(const DirHandle& h) {
|
||||
dev.write(h.posOnDisk, sizeof(DirEntry), (const uint8_t*)&h.entry);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user