feat: MontaukOS installer app, toml config, app directory with manifests, and more

This commit is contained in:
2026-03-08 12:06:29 +01:00
parent 4d0177d55e
commit 1edbec3c66
60 changed files with 3045 additions and 268 deletions
+178 -5
View File
@@ -50,6 +50,9 @@ namespace Fs::Fat32 {
// Location of the 32-byte SFN directory entry on disk
uint64_t sfnPartSector; // partition-relative sector
uint32_t sfnOffInSector; // byte offset within that sector
// Cached position for sequential access (avoids O(n²) chain walks)
uint32_t cachedClusterIdx; // cluster index in chain
uint32_t cachedCluster; // cluster number at that index
};
struct Fat32Instance {
@@ -805,6 +808,8 @@ namespace Fs::Fat32 {
self.files[i].isDirectory = (entry.attributes & ATTR_DIRECTORY) != 0;
self.files[i].sfnPartSector = entry.sfnPartSector;
self.files[i].sfnOffInSector = entry.sfnOffInSector;
self.files[i].cachedClusterIdx = 0;
self.files[i].cachedCluster = entry.firstCluster;
return i;
}
}
@@ -831,15 +836,23 @@ namespace Fs::Fat32 {
uint32_t startClusterIdx = (uint32_t)(offset / clusterSize);
uint32_t clusterOff = (uint32_t)(offset % clusterSize);
// Walk cluster chain to starting cluster
uint32_t cluster = file.firstCluster;
for (uint32_t i = 0; i < startClusterIdx; i++) {
// Walk cluster chain to starting cluster (use cache if possible)
uint32_t cluster;
uint32_t startFrom = 0;
if (file.cachedCluster >= 2 && file.cachedClusterIdx <= startClusterIdx) {
cluster = file.cachedCluster;
startFrom = file.cachedClusterIdx;
} else {
cluster = file.firstCluster;
}
for (uint32_t i = startFrom; i < startClusterIdx; i++) {
cluster = GetNextCluster(self, cluster);
if (IsEndOfChain(cluster)) return 0;
}
// Read data cluster by cluster
uint64_t bytesRead = 0;
uint32_t lastCluster = cluster;
while (bytesRead < size && !IsEndOfChain(cluster)) {
if (!ReadCluster(self, cluster)) break;
@@ -851,9 +864,17 @@ namespace Fs::Fat32 {
bytesRead += toRead;
clusterOff = 0; // subsequent clusters start from offset 0
lastCluster = cluster;
cluster = GetNextCluster(self, cluster);
}
// Update cache
if (bytesRead > 0 && lastCluster >= 2) {
uint32_t endClusterIdx = (uint32_t)((offset + bytesRead - 1) / clusterSize);
file.cachedClusterIdx = endClusterIdx;
file.cachedCluster = lastCluster;
}
return (int)bytesRead;
}
@@ -928,9 +949,18 @@ namespace Fs::Fat32 {
uint32_t clusterIdx = (uint32_t)(offset / clusterSize);
uint32_t clusterOff = (uint32_t)(offset % clusterSize);
uint32_t cluster = file.firstCluster;
// Use cached position if we can skip ahead
uint32_t cluster;
uint32_t prevCluster = 0;
for (uint32_t i = 0; i < clusterIdx; i++) {
uint32_t startIdx = 0;
if (file.cachedCluster >= 2 && file.cachedClusterIdx <= clusterIdx) {
cluster = file.cachedCluster;
startIdx = file.cachedClusterIdx;
} else {
cluster = file.firstCluster;
}
for (uint32_t i = startIdx; i < clusterIdx; i++) {
prevCluster = cluster;
uint32_t next = GetNextCluster(self, cluster);
if (IsEndOfChain(next)) {
@@ -977,6 +1007,13 @@ namespace Fs::Fat32 {
}
done:
// Update cached position for sequential access
if (bytesWritten > 0 && prevCluster >= 2) {
uint32_t endClusterIdx = (uint32_t)((offset + bytesWritten - 1) / clusterSize);
file.cachedClusterIdx = endClusterIdx;
file.cachedCluster = prevCluster;
}
// Update file size if we wrote past the end
uint64_t endPos = offset + bytesWritten;
if (endPos > file.fileSize) {
@@ -1038,6 +1075,8 @@ namespace Fs::Fat32 {
self.files[i].isDirectory = false;
self.files[i].sfnPartSector = existing.sfnPartSector;
self.files[i].sfnOffInSector = existing.sfnOffInSector;
self.files[i].cachedClusterIdx = 0;
self.files[i].cachedCluster = 0;
return i;
}
}
@@ -1124,6 +1163,8 @@ namespace Fs::Fat32 {
self.files[i].isDirectory = false;
self.files[i].sfnPartSector = sfnSector;
self.files[i].sfnOffInSector = sfnOff;
self.files[i].cachedClusterIdx = 0;
self.files[i].cachedCluster = 0;
return i;
}
}
@@ -1258,6 +1299,136 @@ namespace Fs::Fat32 {
return 0;
}
// =========================================================================
// Mkdir — create a directory
// =========================================================================
static int MkdirImpl(int inst, const char* path) {
if (inst < 0 || inst >= g_instanceCount || !g_instances[inst].active) return -1;
auto& self = g_instances[inst];
// Split path into parent directory and new dir name
char parentPath[MaxNameLen];
char dirName[MaxNameLen];
SplitPath(path, parentPath, MaxNameLen, dirName, MaxNameLen);
if (dirName[0] == '\0') return -1;
// Traverse to parent directory
ParsedEntry parentEntry;
if (!TraversePath(inst, parentPath, &parentEntry)) return -1;
if (!(parentEntry.attributes & ATTR_DIRECTORY)) return -1;
uint32_t parentCluster = parentEntry.firstCluster;
// If directory already exists, return success
ParsedEntry existing;
if (FindInDirectory(inst, parentCluster, dirName, &existing)) {
if (existing.attributes & ATTR_DIRECTORY) return 0;
return -1; // exists as a file
}
// Allocate a cluster for the new directory
uint32_t newCluster = AllocateCluster(self);
if (newCluster == 0) return -1;
// Initialize the new directory cluster with . and .. entries
memset(self.clusterBuf, 0, self.clusterSize);
// "." entry — points to itself
uint8_t* dot = self.clusterBuf;
memset(dot, ' ', 11);
dot[0] = '.';
dot[11] = ATTR_DIRECTORY;
uint16_t clHi = (uint16_t)(newCluster >> 16);
uint16_t clLo = (uint16_t)(newCluster & 0xFFFF);
memcpy(dot + 20, &clHi, 2);
memcpy(dot + 26, &clLo, 2);
// ".." entry — points to parent
uint8_t* dotdot = self.clusterBuf + 32;
memset(dotdot, ' ', 11);
dotdot[0] = '.'; dotdot[1] = '.';
dotdot[11] = ATTR_DIRECTORY;
uint32_t parentCl = (parentCluster == self.rootCluster) ? 0 : parentCluster;
clHi = (uint16_t)(parentCl >> 16);
clLo = (uint16_t)(parentCl & 0xFFFF);
memcpy(dotdot + 20, &clHi, 2);
memcpy(dotdot + 26, &clLo, 2);
if (!WriteClusterData(self, newCluster, self.clusterBuf)) return -1;
// Generate 8.3 short name for the directory
char shortName[11];
GenerateShortName(dirName, shortName);
MakeShortNameUnique(inst, parentCluster, shortName);
// Build LFN entries if needed
uint8_t lfnEntries[20 * 32];
int lfnCount = 0;
bool needsLfn = NeedsLfn(dirName, shortName);
if (needsLfn) {
uint8_t checksum = LfnChecksum(shortName);
lfnCount = BuildLfnEntries(dirName, checksum, lfnEntries);
}
int totalSlots = lfnCount + 1;
// Find free directory slots in parent
DirSlotPos pos = FindFreeDirSlots(inst, parentCluster, totalSlots);
if (!pos.found) return -1;
// Build all entries (LFN + SFN)
uint8_t allEntries[21 * 32];
if (lfnCount > 0) {
memcpy(allEntries, lfnEntries, lfnCount * 32);
}
// Build the SFN entry with ATTR_DIRECTORY
uint8_t* sfn = allEntries + lfnCount * 32;
memset(sfn, 0, 32);
memcpy(sfn, shortName, 11);
sfn[11] = ATTR_DIRECTORY;
clHi = (uint16_t)(newCluster >> 16);
clLo = (uint16_t)(newCluster & 0xFFFF);
memcpy(sfn + 20, &clHi, 2);
memcpy(sfn + 26, &clLo, 2);
// Directory size field is 0 per FAT spec
// Write entries to disk
uint64_t curSector = pos.partSector;
uint32_t curOff = pos.offsetInSec;
uint8_t sectorBuf[512];
if (!ReadPartSectors(self, curSector, 1, sectorBuf)) return -1;
int bytesTotal = totalSlots * 32;
int written = 0;
while (written < bytesTotal) {
int space = (int)self.bytesPerSector - (int)curOff;
int chunk = bytesTotal - written;
if (chunk > space) chunk = space;
memcpy(sectorBuf + curOff, allEntries + written, chunk);
written += chunk;
if (written < bytesTotal || chunk == space) {
if (!WritePartSectors(self, curSector, 1, sectorBuf)) return -1;
if (written < bytesTotal) {
curSector++;
curOff = 0;
if (!ReadPartSectors(self, curSector, 1, sectorBuf)) return -1;
}
} else {
if (!WritePartSectors(self, curSector, 1, sectorBuf)) return -1;
}
}
return 0;
}
// =========================================================================
// Template thunks — generate unique function pointers per instance
// =========================================================================
@@ -1271,6 +1442,7 @@ namespace Fs::Fat32 {
static int Write(int h, const uint8_t* b, uint64_t o, uint64_t s) { return WriteImpl(N, h, b, o, s); }
static int Create(const char* p) { return CreateImpl(N, p); }
static int Delete(const char* p) { return DeleteImpl(N, p); }
static int Mkdir(const char* p) { return MkdirImpl(N, p); }
};
template<int N>
@@ -1284,6 +1456,7 @@ namespace Fs::Fat32 {
Thunks<N>::Write,
Thunks<N>::Create,
Thunks<N>::Delete,
Thunks<N>::Mkdir,
};
}