Files
ESP8266lib/ext/sd/fat32/DirHelper.h
2021-02-21 21:04:11 +01:00

131 lines
2.8 KiB
C++

#pragma once
class DirHelper {
static constexpr const char* NAME = "FAT32_DirH";
public:
enum class CreateType {
NONE,
DIR,
FILE
};
/**
* get (or allocate, if needed) a new DirEntry with the given name absolute name
* if the entry is allocated, it is UNTYPED
* name: e.g. /path1/path2/path3 or /path1/path2/file.txt
*/
static DirHandle getOrCreate(FS& fs, ClusterNr dirStartCluster, const std::string& absName, CreateType ct) {
// determine the local name
Split s = split(absName);
{ // search for a matching existing entry
DirIterator di(fs, dirStartCluster);
while(true) {
DirHandle h = di.nextUsable();
if (!h.isValid()) {break;}
// found a matching entry
const std::string n = h.getName();
if (n == s.first) {
// are we done yet?
if (s.hasMore()) {
const ClusterNr subDirStartCluster = h.getFirstCluster();
return getOrCreate(fs, subDirStartCluster, s.next, ct);
} else {
return h;
}
}
}
}
// no matching entry found
if (ct == CreateType::NONE) {return DirHandle::invalid();}
{ // allocate a new DirEntry within the current directory
DirIterator di(fs, dirStartCluster);
DirHandle h = di.nextFree();
h.setName(s.first);
h.setSize(0);
h.setFirstCluster(0);
// if this is a sub-directory, allocate a new cluster for it
if (s.hasMore() || ct == CreateType::DIR) {
// allocate a cluster where the directory contents are to be stored
ClusterNr freeCluster = fs.allocFreeCluster(0);
h.setFirstCluster(freeCluster);
h.setDirectory();
fs.write(h);
// ensure the new cluster is initialized with all zeros (this is also equal to an immediate END_OF_DIRECTORY marker in the beginning
fs.zeroOutCluster(freeCluster);
DirIterator di2(fs, freeCluster);
// create the "." entry (pointer to current directory)
DirHandle h2 = di2.next();
h2.setDot(freeCluster);
fs.write(h2);
// create the ".." entry (pointer to parent directory)
DirHandle h3 = di2.next();
h3.setDotDot(dirStartCluster);
fs.write(h3);
// more path to process?
if (s.hasMore()) {
return getOrCreate(fs, freeCluster, s.next, ct);
} else {
return h;
}
} else {
fs.write(h);
return h;
}
}
}
private:
struct Split {
std::string first;
std::string next;
Split(const std::string& first, const std::string& next) : first(first), next(next) {}
bool hasMore() const {return !next.empty();}
};
/** split "/path1/path2/path3/file.txt" into "path1" and "path2/path3/file.txt" */
static Split split(std::string absPath) {
if (absPath[0] == '/') {
absPath = absPath.substr(1);
}
std::size_t pos = absPath.find('/');
if (pos == std::string::npos) {
return Split(absPath, "");
} else {
return Split(absPath.substr(0, pos), absPath.substr(pos));
}
}
};