154 lines
3.1 KiB
C++
154 lines
3.1 KiB
C++
class DirIterator {
|
|
|
|
static constexpr const char* NAME = "FAT32_DirI";
|
|
|
|
FS& fs;
|
|
ClusterNr curCluster;
|
|
uint8_t curEntryInSector; // current DirEntry within the current sector
|
|
uint8_t curSectorInCluster; // current Sector within the current cluster
|
|
|
|
uint8_t buf[512];
|
|
|
|
public:
|
|
|
|
DirIterator(FS& fs, ClusterNr clusterNr) : fs(fs), curCluster(clusterNr), curEntryInSector(0), curSectorInCluster(0) {
|
|
|
|
Log::addInfo(NAME, "init @ Cluster %d", curCluster);
|
|
|
|
// read the first sector in the first cluster
|
|
read(curCluster, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** get the next usable entry within the current directory */
|
|
DirEntryAt nextUsable() {
|
|
|
|
while(true) {
|
|
|
|
DirEntryAt dea = next(false);
|
|
|
|
// check it
|
|
if (!dea.isValid()) {return DirEntryAt::invalid();}
|
|
if (dea.isLongFileName()) {continue;}
|
|
if (dea.isUnused()) {continue;}
|
|
if (dea.isEndOfDirectory()) {return DirEntryAt::invalid();}
|
|
|
|
// usable!
|
|
return dea;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** get (or create) a free entry within the current directory */
|
|
DirEntryAt nextFree() {
|
|
|
|
while(true) {
|
|
|
|
DirEntryAt dea = next(true);
|
|
|
|
// check it
|
|
if (!dea.isValid()) {return DirEntryAt::invalid();}
|
|
|
|
if (dea.isUnused()) {
|
|
|
|
// switch from "unused" to something usable
|
|
//dea.setName("NEW.ONE");
|
|
//dea.entry.attr.raw = 0;
|
|
//return dea;
|
|
|
|
}
|
|
|
|
if (dea.isEndOfDirectory()) {
|
|
|
|
// add a new EndOfDirectory entry afterwards
|
|
DirEntryAt dea2 = next(true);
|
|
dea2.setEndOfDirectory();
|
|
fs.write(dea2);
|
|
|
|
// switch from "end of directory" to something usable
|
|
dea.setName("NEW.ONE");
|
|
dea.entry.attr.raw = 0;
|
|
return dea;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
DirEntryAt cur() {
|
|
AbsPos pos = fs.clusterToAbsPos(curCluster) + (curSectorInCluster * fs.desc.bytesPerSector) + (curEntryInSector * sizeof(DirEntry));
|
|
DirEntry* dirEntry = reinterpret_cast<DirEntry*>(buf + (curEntryInSector * sizeof(DirEntry)));
|
|
return DirEntryAt(pos, dirEntry);
|
|
}
|
|
|
|
DirEntryAt next(bool allocIfNeeded) {
|
|
|
|
while(true) {
|
|
|
|
// end of sector reached?
|
|
if (curEntryInSector >= fs.tmp.dirEntriesPerSector) {
|
|
|
|
// next sector
|
|
++curSectorInCluster;
|
|
curEntryInSector = 0;
|
|
|
|
// end of cluster reached?
|
|
if (curSectorInCluster >= fs.desc.sectorsPerCluster) {
|
|
|
|
// find next cluster (if any)
|
|
const ClusterNr nextCluster = fs.getNextCluster(curCluster);
|
|
|
|
// reached end of clusters?
|
|
if (nextCluster.isEndOfClusters()) {
|
|
|
|
// do not alloc new entries? -> done here
|
|
if (!allocIfNeeded) {
|
|
return DirEntryAt::invalid();
|
|
} else {
|
|
curCluster = fs.allocFreeCluster(curCluster);
|
|
}
|
|
|
|
} else {
|
|
curCluster = nextCluster;
|
|
}
|
|
|
|
curSectorInCluster = 0;
|
|
|
|
}
|
|
|
|
// fetch from disk
|
|
read(curCluster, curSectorInCluster);
|
|
|
|
}
|
|
|
|
// the current entry
|
|
DirEntryAt dea = cur();
|
|
++curEntryInSector;
|
|
|
|
return dea;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
/** fetch one sector within a cluster */
|
|
void read(ClusterNr clusterNr, uint8_t sectorInCluster) {
|
|
Log::addInfo(NAME, "fetching sector %d in clusterNr %d", sectorInCluster, clusterNr) ;
|
|
const AbsPos pos = fs.clusterToAbsPos(clusterNr) + (curSectorInCluster * fs.desc.bytesPerSector);
|
|
fs.dev.read(pos, fs.desc.bytesPerSector, buf);
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|