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); // ".." folders point to cluster 0 if they point to the root folder -> adjust here if (clusterNr == 0) { clusterNr = fs.desc.rootDirFirstCluster; } // read the first sector in the first cluster read(curCluster, 0); } DirIterator(FS& fs, DirHandle dh) : DirIterator(fs, dh.getFirstCluster()) { } /** get the next usable entry within the current directory */ DirHandle nextUsable() { while(true) { DirHandle h = next(false); // check it if (!h.isValid()) {return DirHandle::invalid();} if (h.isLongFileName()) {continue;} if (h.isUnused()) {continue;} if (h.isEndOfDirectory()) {return DirHandle::invalid();} // usable! return h; } } /** get (or create) a free entry within the current directory */ DirHandle nextFree() { while(true) { DirHandle h = next(true); // check it if (!h.isValid()) {return DirHandle::invalid();} if (h.isUnused()) { // switch from "unused" to something usable //h.setName("NEW.ONE"); //h.entry.attr.raw = 0; //return dea; } if (h.isEndOfDirectory()) { // add a new EndOfDirectory entry afterwards DirHandle h2 = next(true); h2.setEndOfDirectory(); fs.write(h2); // switch from "end of directory" to something usable h.setName("NEW.ONE"); h.entry.attr.raw = 0; return h; } } } DirHandle next() { return next(false); } private: DirHandle cur() { AbsPos pos = fs.clusterToAbsPos(curCluster) + (curSectorInCluster * fs.desc.bytesPerSector) + (curEntryInSector * sizeof(DirEntry)); DirEntry* dirEntry = reinterpret_cast(buf + (curEntryInSector * sizeof(DirEntry))); return DirHandle(pos, dirEntry); } DirHandle 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 DirHandle::invalid(); } else { curCluster = fs.allocFreeCluster(curCluster); } } else { curCluster = nextCluster; } curSectorInCluster = 0; } // fetch from disk read(curCluster, curSectorInCluster); } // the current entry DirHandle h = cur(); ++curEntryInSector; return h; } } 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); } };