worked on FAT stuff and tests
This commit is contained in:
130
ext/sd/fat32/DirHelper.h
Normal file
130
ext/sd/fat32/DirHelper.h
Normal file
@@ -0,0 +1,130 @@
|
||||
#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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user