fix: fix filesystem stack regression
This commit is contained in:
+64
-16
@@ -695,6 +695,14 @@ namespace Fs::Ext2 {
|
|||||||
uint8_t fileType;
|
uint8_t fileType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool IsValidDirEntry(const DirEntry* de, uint32_t pos, uint32_t remaining) {
|
||||||
|
if (de->rec_len == 0) return false;
|
||||||
|
if (de->rec_len < sizeof(DirEntry)) return false;
|
||||||
|
if (pos + de->rec_len > remaining) return false;
|
||||||
|
if (de->name_len > de->rec_len - sizeof(DirEntry)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Find a single entry by name in a directory inode.
|
// Find a single entry by name in a directory inode.
|
||||||
static bool FindInDirectory(Ext2Instance& inst, const Inode& dirInode,
|
static bool FindInDirectory(Ext2Instance& inst, const Inode& dirInode,
|
||||||
const char* name, ParsedEntry* out) {
|
const char* name, ParsedEntry* out) {
|
||||||
@@ -718,8 +726,7 @@ namespace Fs::Ext2 {
|
|||||||
|
|
||||||
while (pos + 8 <= remaining) {
|
while (pos + 8 <= remaining) {
|
||||||
DirEntry* de = (DirEntry*)(dirBuf + pos);
|
DirEntry* de = (DirEntry*)(dirBuf + pos);
|
||||||
if (de->rec_len == 0) break;
|
if (!IsValidDirEntry(de, pos, remaining)) break;
|
||||||
if (de->rec_len < 8 || pos + de->rec_len > blockSize) break;
|
|
||||||
|
|
||||||
if (de->inode != 0 && de->name_len > 0) {
|
if (de->inode != 0 && de->name_len > 0) {
|
||||||
char entryName[MaxNameLen];
|
char entryName[MaxNameLen];
|
||||||
@@ -767,8 +774,7 @@ namespace Fs::Ext2 {
|
|||||||
|
|
||||||
while (pos + 8 <= remaining && count < maxEntries) {
|
while (pos + 8 <= remaining && count < maxEntries) {
|
||||||
DirEntry* de = (DirEntry*)(dirBuf + pos);
|
DirEntry* de = (DirEntry*)(dirBuf + pos);
|
||||||
if (de->rec_len == 0) break;
|
if (!IsValidDirEntry(de, pos, remaining)) break;
|
||||||
if (de->rec_len < 8 || pos + de->rec_len > blockSize) break;
|
|
||||||
|
|
||||||
if (de->inode != 0 && de->name_len > 0) {
|
if (de->inode != 0 && de->name_len > 0) {
|
||||||
int nameLen = de->name_len;
|
int nameLen = de->name_len;
|
||||||
@@ -798,6 +804,59 @@ namespace Fs::Ext2 {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ReadDirectoryNames(Ext2Instance& inst, const Inode& dirInode,
|
||||||
|
char outNames[MaxDirEntries][MaxNameLen],
|
||||||
|
int maxEntries) {
|
||||||
|
uint32_t dirSize = dirInode.i_size;
|
||||||
|
uint32_t blockSize = inst.blockSize;
|
||||||
|
uint32_t numBlocks = (dirSize + blockSize - 1) / blockSize;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
uint8_t* dirBuf = (uint8_t*)Memory::g_pfa->AllocateZeroed();
|
||||||
|
if (!dirBuf) return 0;
|
||||||
|
|
||||||
|
for (uint32_t bi = 0; bi < numBlocks && count < maxEntries; bi++) {
|
||||||
|
uint32_t physBlock = GetPhysicalBlock(inst, dirInode, bi);
|
||||||
|
if (physBlock == 0) continue;
|
||||||
|
if (!ReadBlock(inst, physBlock, dirBuf)) continue;
|
||||||
|
|
||||||
|
uint32_t pos = 0;
|
||||||
|
uint32_t remaining = dirSize - bi * blockSize;
|
||||||
|
if (remaining > blockSize) remaining = blockSize;
|
||||||
|
|
||||||
|
while (pos + 8 <= remaining && count < maxEntries) {
|
||||||
|
DirEntry* de = (DirEntry*)(dirBuf + pos);
|
||||||
|
if (!IsValidDirEntry(de, pos, remaining)) break;
|
||||||
|
|
||||||
|
if (de->inode != 0 && de->name_len > 0) {
|
||||||
|
int nameLen = de->name_len;
|
||||||
|
if (nameLen >= MaxNameLen) nameLen = MaxNameLen - 1;
|
||||||
|
memcpy(outNames[count], (uint8_t*)de + sizeof(DirEntry), nameLen);
|
||||||
|
outNames[count][nameLen] = '\0';
|
||||||
|
|
||||||
|
if (outNames[count][0] == '.' &&
|
||||||
|
(outNames[count][1] == '\0' ||
|
||||||
|
(outNames[count][1] == '.' && outNames[count][2] == '\0'))) {
|
||||||
|
pos += de->rec_len;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (de->file_type == EXT2_FT_DIR && nameLen < MaxNameLen - 1) {
|
||||||
|
outNames[count][nameLen++] = '/';
|
||||||
|
outNames[count][nameLen] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += de->rec_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory::g_pfa->Free(dirBuf);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
// Add a directory entry to a directory inode
|
// Add a directory entry to a directory inode
|
||||||
static bool AddDirEntry(Ext2Instance& inst, uint32_t dirInodeNum, Inode& dirInode,
|
static bool AddDirEntry(Ext2Instance& inst, uint32_t dirInodeNum, Inode& dirInode,
|
||||||
uint32_t childInodeNum, const char* name, uint8_t fileType) {
|
uint32_t childInodeNum, const char* name, uint8_t fileType) {
|
||||||
@@ -1096,22 +1155,11 @@ namespace Fs::Ext2 {
|
|||||||
if (!TraversePath(self, path, &inodeNum, &inode)) return -1;
|
if (!TraversePath(self, path, &inodeNum, &inode)) return -1;
|
||||||
if ((inode.i_mode & IMODE_TYPE_MASK) != IMODE_DIR) return -1;
|
if ((inode.i_mode & IMODE_TYPE_MASK) != IMODE_DIR) return -1;
|
||||||
|
|
||||||
ParsedEntry entries[MaxDirEntries];
|
|
||||||
int limit = maxEntries < MaxDirEntries ? maxEntries : MaxDirEntries;
|
int limit = maxEntries < MaxDirEntries ? maxEntries : MaxDirEntries;
|
||||||
int count = ReadDirectoryEntries(self, inode, entries, limit);
|
int count = ReadDirectoryNames(self, inode, self.dirNames, limit);
|
||||||
|
|
||||||
self.dirNameCount = count;
|
self.dirNameCount = count;
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
int j = 0;
|
|
||||||
while (entries[i].name[j] && j < MaxNameLen - 2) {
|
|
||||||
self.dirNames[i][j] = entries[i].name[j];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
// Append trailing '/' for directories so userspace can distinguish them
|
|
||||||
if (entries[i].fileType == EXT2_FT_DIR && j < MaxNameLen - 1) {
|
|
||||||
self.dirNames[i][j++] = '/';
|
|
||||||
}
|
|
||||||
self.dirNames[i][j] = '\0';
|
|
||||||
outNames[i] = self.dirNames[i];
|
outNames[i] = self.dirNames[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+74
-13
@@ -672,6 +672,79 @@ namespace Fs::Fat32 {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ReadDirectoryNames(int inst, uint32_t dirCluster,
|
||||||
|
char outNames[MaxDirEntries][MaxNameLen],
|
||||||
|
int maxEntries) {
|
||||||
|
auto& self = g_instances[inst];
|
||||||
|
uint16_t lfnBuf[MaxNameLen];
|
||||||
|
bool hasLfn = false;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
uint32_t cluster = dirCluster;
|
||||||
|
while (!IsEndOfChain(cluster) && count < maxEntries) {
|
||||||
|
if (!ReadCluster(self, cluster)) break;
|
||||||
|
|
||||||
|
int perCluster = (int)(self.clusterSize / 32);
|
||||||
|
for (int i = 0; i < perCluster && count < maxEntries; i++) {
|
||||||
|
uint8_t* e = self.clusterBuf + i * 32;
|
||||||
|
|
||||||
|
if (e[0] == 0x00) return count;
|
||||||
|
if (e[0] == 0xE5) { hasLfn = false; continue; }
|
||||||
|
|
||||||
|
uint8_t attr = e[11];
|
||||||
|
|
||||||
|
if (attr == ATTR_LFN) {
|
||||||
|
uint8_t seq = e[0];
|
||||||
|
int seqNum = seq & 0x1F;
|
||||||
|
|
||||||
|
if (seq & 0x40) {
|
||||||
|
for (int k = 0; k < MaxNameLen; k++) lfnBuf[k] = 0;
|
||||||
|
hasLfn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasLfn && seqNum >= 1 && seqNum <= 20) {
|
||||||
|
uint16_t chars[13];
|
||||||
|
ExtractLfnChars(e, chars);
|
||||||
|
int offset = (seqNum - 1) * 13;
|
||||||
|
for (int k = 0; k < 13 && offset + k < MaxNameLen; k++) {
|
||||||
|
lfnBuf[offset + k] = chars[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr & ATTR_VOLUME_ID) { hasLfn = false; continue; }
|
||||||
|
|
||||||
|
if (hasLfn) {
|
||||||
|
Utf16ToAscii(lfnBuf, MaxNameLen, outNames[count]);
|
||||||
|
} else {
|
||||||
|
ParseShortName(e, outNames[count]);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasLfn = false;
|
||||||
|
|
||||||
|
if (outNames[count][0] == '.' &&
|
||||||
|
(outNames[count][1] == '\0' ||
|
||||||
|
(outNames[count][1] == '.' && outNames[count][2] == '\0'))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = 0;
|
||||||
|
while (outNames[count][len] && len < MaxNameLen - 2) len++;
|
||||||
|
if ((attr & ATTR_DIRECTORY) && len < MaxNameLen - 1) {
|
||||||
|
outNames[count][len++] = '/';
|
||||||
|
outNames[count][len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster = GetNextCluster(self, cluster);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Case-insensitive string comparison
|
// Case-insensitive string comparison
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -932,23 +1005,11 @@ namespace Fs::Fat32 {
|
|||||||
if (!TraversePath(inst, path, &dirEntry)) return -1;
|
if (!TraversePath(inst, path, &dirEntry)) return -1;
|
||||||
if (!(dirEntry.attributes & ATTR_DIRECTORY)) return -1;
|
if (!(dirEntry.attributes & ATTR_DIRECTORY)) return -1;
|
||||||
|
|
||||||
ParsedEntry entries[MaxDirEntries];
|
|
||||||
int limit = maxEntries < MaxDirEntries ? maxEntries : MaxDirEntries;
|
int limit = maxEntries < MaxDirEntries ? maxEntries : MaxDirEntries;
|
||||||
int count = ReadDirectory(inst, dirEntry.firstCluster, entries, limit);
|
int count = ReadDirectoryNames(inst, dirEntry.firstCluster, self.dirNames, limit);
|
||||||
|
|
||||||
// Copy names into persistent cache
|
|
||||||
self.dirNameCount = count;
|
self.dirNameCount = count;
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
int j = 0;
|
|
||||||
while (entries[i].name[j] && j < MaxNameLen - 2) {
|
|
||||||
self.dirNames[i][j] = entries[i].name[j];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
// Append trailing '/' for directories so userspace can distinguish them
|
|
||||||
if ((entries[i].attributes & ATTR_DIRECTORY) && j < MaxNameLen - 1) {
|
|
||||||
self.dirNames[i][j++] = '/';
|
|
||||||
}
|
|
||||||
self.dirNames[i][j] = '\0';
|
|
||||||
outNames[i] = self.dirNames[i];
|
outNames[i] = self.dirNames[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user