fix: fix ramdisk readdir inconsistency.
This commit is contained in:
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MONTAUK_BUILD_NUMBER 108
|
#define MONTAUK_BUILD_NUMBER 109
|
||||||
|
|||||||
@@ -262,6 +262,10 @@ namespace Fs::Ramdisk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ReadDirAt(const char* path, const char** outNames, int maxEntries, int startIndex) {
|
int ReadDirAt(const char* path, const char** outNames, int maxEntries, int startIndex) {
|
||||||
|
if (path == nullptr || outNames == nullptr || maxEntries < 0 || startIndex < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Reject outright if path names an existing regular file: without this,
|
// Reject outright if path names an existing regular file: without this,
|
||||||
// a file with no matching "path/..." children below falls through to
|
// a file with no matching "path/..." children below falls through to
|
||||||
// the child-scan loop and returns 0 (empty), which callers that use
|
// the child-scan loop and returns 0 (empty), which callers that use
|
||||||
@@ -269,10 +273,10 @@ namespace Fs::Ramdisk {
|
|||||||
int selfIdx = FindEntryByPath(path);
|
int selfIdx = FindEntryByPath(path);
|
||||||
if (selfIdx >= 0 && !fileTable[selfIdx].isDirectory) return -1;
|
if (selfIdx >= 0 && !fileTable[selfIdx].isDirectory) return -1;
|
||||||
|
|
||||||
// Normalize path: skip leading '/'
|
char normalized[MaxNameLen];
|
||||||
if (path[0] == '/') path++;
|
int pathLen = NormalizePath(path, normalized, MaxNameLen);
|
||||||
|
if (pathLen < 0) return -1;
|
||||||
int pathLen = StrLen(path);
|
path = normalized;
|
||||||
int count = 0; // entries written to outNames
|
int count = 0; // entries written to outNames
|
||||||
int seen = 0; // matching direct children scanned so far (for startIndex skip)
|
int seen = 0; // matching direct children scanned so far (for startIndex skip)
|
||||||
|
|
||||||
@@ -280,6 +284,7 @@ namespace Fs::Ramdisk {
|
|||||||
const char* entryName = fileTable[i].name;
|
const char* entryName = fileTable[i].name;
|
||||||
bool isChild = false;
|
bool isChild = false;
|
||||||
|
|
||||||
|
const char* childName = entryName;
|
||||||
if (pathLen == 0) {
|
if (pathLen == 0) {
|
||||||
// Root directory: find entries without '/' in them (or only trailing '/')
|
// Root directory: find entries without '/' in them (or only trailing '/')
|
||||||
bool hasSlash = false;
|
bool hasSlash = false;
|
||||||
@@ -311,11 +316,14 @@ namespace Fs::Ramdisk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
isChild = (!hasDeepSlash && restLen > 0);
|
isChild = (!hasDeepSlash && restLen > 0);
|
||||||
|
childName = rest;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isChild) continue;
|
if (!isChild) continue;
|
||||||
if (seen++ < startIndex) continue; // skip entries before the requested page
|
if (seen++ < startIndex) continue; // skip entries before the requested page
|
||||||
outNames[count++] = entryName;
|
// ReadDir follows the same contract as ext2/FAT32: return the
|
||||||
|
// direct child's name, not its archive path relative to root.
|
||||||
|
outNames[count++] = childName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A path with no directory entry and no children does not exist.
|
// A path with no directory entry and no children does not exist.
|
||||||
|
|||||||
@@ -269,8 +269,8 @@ void filemanager_read_dir(FileManagerState* fm) {
|
|||||||
fm->virtual_view = FM_VIRTUAL_VIEW_NONE;
|
fm->virtual_view = FM_VIRTUAL_VIEW_NONE;
|
||||||
fm->entry_count = 0;
|
fm->entry_count = 0;
|
||||||
|
|
||||||
// readdir returns full paths from the VFS (e.g. "man/fetch.1" instead
|
// Current drivers return direct-child names. Retain prefix stripping for
|
||||||
// of just "fetch.1"). Compute the prefix to strip so we get basenames.
|
// compatibility with images built against the older ramdisk behavior.
|
||||||
const char* after_drive = fm->current_path;
|
const char* after_drive = fm->current_path;
|
||||||
for (int k = 0; after_drive[k]; k++) {
|
for (int k = 0; after_drive[k]; k++) {
|
||||||
if (after_drive[k] == ':' && after_drive[k + 1] == '/') {
|
if (after_drive[k] == ':' && after_drive[k + 1] == '/') {
|
||||||
@@ -433,7 +433,7 @@ void filemanager_read_system_configuration(FileManagerState* fm) {
|
|||||||
static int filemanager_read_all_children(const char* dir, char (**out)[256]) {
|
static int filemanager_read_all_children(const char* dir, char (**out)[256]) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
|
|
||||||
// Compute the prefix to strip (readdir returns drive-root-relative paths).
|
// Retain support for older ramdisks that returned drive-root-relative paths.
|
||||||
const char* after_drive = dir;
|
const char* after_drive = dir;
|
||||||
for (int k = 0; after_drive[k]; k++) {
|
for (int k = 0; after_drive[k]; k++) {
|
||||||
if (after_drive[k] == ':' && after_drive[k + 1] == '/') {
|
if (after_drive[k] == ':' && after_drive[k + 1] == '/') {
|
||||||
|
|||||||
@@ -14,9 +14,8 @@
|
|||||||
// App Manifest Scanning
|
// App Manifest Scanning
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Extract the basename from a readdir entry.
|
// Extract the basename from a readdir entry, tolerating both current
|
||||||
// readdir returns full paths from drive root (e.g. "apps/doom/") —
|
// direct-child names and paths returned by older ramdisk kernels.
|
||||||
// strip the directory prefix and any trailing slash to get just "doom".
|
|
||||||
static void extract_basename(char* out, int outSz, const char* entry) {
|
static void extract_basename(char* out, int outSz, const char* entry) {
|
||||||
// Strip trailing slash
|
// Strip trailing slash
|
||||||
int len = montauk::slen(entry);
|
int len = montauk::slen(entry);
|
||||||
@@ -89,7 +88,7 @@ void desktop_scan_apps(DesktopState* ds) {
|
|||||||
scanned += got;
|
scanned += got;
|
||||||
|
|
||||||
for (int i = 0; i < got; i++) {
|
for (int i = 0; i < got; i++) {
|
||||||
// readdir returns paths like "apps/doom/" — extract just "doom"
|
// Strip the directory marker and tolerate old root-relative entries.
|
||||||
char dirname[64];
|
char dirname[64];
|
||||||
extract_basename(dirname, sizeof(dirname), entries[i]);
|
extract_basename(dirname, sizeof(dirname), entries[i]);
|
||||||
if (dirname[0] == '\0') continue;
|
if (dirname[0] == '\0') continue;
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ inline void wallpaper_scan_dir(const char* dir_path, WallpaperFileList* list,
|
|||||||
int total = montauk::readdir(dir_path, raw_names, 64);
|
int total = montauk::readdir(dir_path, raw_names, 64);
|
||||||
if (total <= 0) return;
|
if (total <= 0) return;
|
||||||
|
|
||||||
// Compute prefix to strip (readdir returns full paths from VFS root)
|
// Retain support for older ramdisks that returned paths from the VFS root.
|
||||||
const char* after_drive = dir_path;
|
const char* after_drive = dir_path;
|
||||||
for (int k = 0; after_drive[k]; k++) {
|
for (int k = 0; after_drive[k]; k++) {
|
||||||
if (after_drive[k] == ':' && after_drive[k + 1] == '/') {
|
if (after_drive[k] == ':' && after_drive[k + 1] == '/') {
|
||||||
|
|||||||
@@ -124,23 +124,54 @@ bool installer_list_dir(const char* abs_dir, DirList* out) {
|
|||||||
int scanned = 0;
|
int scanned = 0;
|
||||||
int capacity = 0;
|
int capacity = 0;
|
||||||
|
|
||||||
|
// The filesystem API returns direct-child names. Keep this installer's
|
||||||
|
// historical root-relative representation because component filtering
|
||||||
|
// and recursive source paths operate on paths such as "sdk/tcc".
|
||||||
|
const char* dir_rel = abs_dir;
|
||||||
|
for (int i = 0; dir_rel[i]; i++) {
|
||||||
|
if (dir_rel[i] == ':') {
|
||||||
|
dir_rel += i + 1;
|
||||||
|
if (dir_rel[0] == '/') dir_rel++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int dir_rel_len = slen(dir_rel);
|
||||||
|
while (dir_rel_len > 0 && dir_rel[dir_rel_len - 1] == '/') dir_rel_len--;
|
||||||
|
|
||||||
int got = montauk::readdir_at(abs_dir, batch, BATCH, 0);
|
int got = montauk::readdir_at(abs_dir, batch, BATCH, 0);
|
||||||
if (got < 0) return false;
|
if (got < 0) return false;
|
||||||
|
|
||||||
while (got > 0) {
|
while (got > 0) {
|
||||||
for (int i = 0; i < got; i++) {
|
for (int i = 0; i < got; i++) {
|
||||||
const char* raw = batch[i];
|
const char* raw = batch[i];
|
||||||
int len = slen(raw);
|
int raw_len = slen(raw);
|
||||||
|
|
||||||
bool is_dir = (len > 0 && raw[len - 1] == '/');
|
bool is_dir = (raw_len > 0 && raw[raw_len - 1] == '/');
|
||||||
if (is_dir) len--;
|
if (is_dir) raw_len--;
|
||||||
if (len <= 0) continue;
|
if (raw_len <= 0) continue;
|
||||||
|
|
||||||
|
bool already_root_relative = false;
|
||||||
|
if (dir_rel_len > 0 && raw_len > dir_rel_len &&
|
||||||
|
raw[dir_rel_len] == '/') {
|
||||||
|
already_root_relative = true;
|
||||||
|
for (int k = 0; k < dir_rel_len; k++) {
|
||||||
|
if (raw[k] != dir_rel[k]) {
|
||||||
|
already_root_relative = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = raw_len;
|
||||||
|
if (dir_rel_len > 0 && !already_root_relative) {
|
||||||
|
len += dir_rel_len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip "." and ".."
|
// Skip "." and ".."
|
||||||
const char* base = raw;
|
const char* base = raw;
|
||||||
for (int k = 0; k < len; k++)
|
for (int k = 0; k < raw_len; k++)
|
||||||
if (raw[k] == '/') base = raw + k + 1;
|
if (raw[k] == '/') base = raw + k + 1;
|
||||||
int base_len = (int)(len - (base - raw));
|
int base_len = (int)(raw_len - (base - raw));
|
||||||
if (base_len == 1 && base[0] == '.') continue;
|
if (base_len == 1 && base[0] == '.') continue;
|
||||||
if (base_len == 2 && base[0] == '.' && base[1] == '.') continue;
|
if (base_len == 2 && base[0] == '.' && base[1] == '.') continue;
|
||||||
|
|
||||||
@@ -156,7 +187,13 @@ bool installer_list_dir(const char* abs_dir, DirList* out) {
|
|||||||
|
|
||||||
char* rel = (char*)montauk::malloc(len + 1);
|
char* rel = (char*)montauk::malloc(len + 1);
|
||||||
if (!rel) { installer_free_dir_list(out); return false; }
|
if (!rel) { installer_free_dir_list(out); return false; }
|
||||||
montauk::memcpy(rel, raw, len);
|
int pos = 0;
|
||||||
|
if (dir_rel_len > 0 && !already_root_relative) {
|
||||||
|
montauk::memcpy(rel, dir_rel, dir_rel_len);
|
||||||
|
pos = dir_rel_len;
|
||||||
|
rel[pos++] = '/';
|
||||||
|
}
|
||||||
|
montauk::memcpy(rel + pos, raw, raw_len);
|
||||||
rel[len] = '\0';
|
rel[len] = '\0';
|
||||||
|
|
||||||
out->entries[out->count].rel = rel;
|
out->entries[out->count].rel = rel;
|
||||||
|
|||||||
@@ -284,10 +284,10 @@ void do_install();
|
|||||||
void do_update();
|
void do_update();
|
||||||
bool installer_path_exists(const char* abs_path);
|
bool installer_path_exists(const char* abs_path);
|
||||||
|
|
||||||
// Heap-backed directory listing. Entries are full paths relative to the
|
// Heap-backed directory listing. Direct-child names from readdir are expanded
|
||||||
// drive root (e.g. "apps/doom"), with is_dir derived from the trailing '/'
|
// to paths relative to the drive root (e.g. "apps/doom"), with is_dir derived
|
||||||
// the VFS appends to directory names. Survives nested listings, unlike the
|
// from the trailing '/' the VFS appends to directory names. Survives nested
|
||||||
// kernel's rotating readdir scratch pages.
|
// listings, unlike the kernel's rotating readdir scratch pages.
|
||||||
struct DirEntry {
|
struct DirEntry {
|
||||||
char* rel; // path relative to drive root, no trailing '/'
|
char* rel; // path relative to drive root, no trailing '/'
|
||||||
bool is_dir;
|
bool is_dir;
|
||||||
|
|||||||
@@ -622,8 +622,8 @@ void wp_load_fonts() {
|
|||||||
if (!raw) continue;
|
if (!raw) continue;
|
||||||
int rl = montauk::slen(raw);
|
int rl = montauk::slen(raw);
|
||||||
if (rl == 0 || raw[rl - 1] == '/') continue; // skip directories
|
if (rl == 0 || raw[rl - 1] == '/') continue; // skip directories
|
||||||
// readdir may return a full internal path (ramdisk) or a bare name;
|
// Current drivers return a bare name; accepting an older ramdisk's
|
||||||
// take everything after the last '/'.
|
// internal path here is harmless and keeps mixed images compatible.
|
||||||
const char* base = raw;
|
const char* base = raw;
|
||||||
for (int k = 0; raw[k]; k++) if (raw[k] == '/') base = raw + k + 1;
|
for (int k = 0; raw[k]; k++) if (raw[k] == '/') base = raw + k + 1;
|
||||||
wp_register_font_file(base);
|
wp_register_font_file(base);
|
||||||
|
|||||||
Reference in New Issue
Block a user