void (*open)(struct fs_node* node);
void (*close)(struct fs_node* node);
struct fs_node* (*finddir)(struct fs_node* node, const char* name);
+ int (*readdir)(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len);
} fs_node_t;
+struct vfs_dirent {
+ uint32_t d_ino;
+ uint16_t d_reclen;
+ uint8_t d_type;
+ char d_name[24];
+};
+
// Standard VFS functions
uint32_t vfs_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer);
uint32_t vfs_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
return 0;
}
+static int devfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len) {
+ (void)node;
+ if (!inout_index || !buf) return -1;
+ if (buf_len < sizeof(struct vfs_dirent)) return -1;
+
+ static const struct { const char* name; uint32_t ino; uint8_t type; } devs[] = {
+ { "null", 2, FS_CHARDEVICE },
+ { "tty", 3, FS_CHARDEVICE },
+ { "ptmx", 4, FS_CHARDEVICE },
+ { "pts", 5, FS_DIRECTORY },
+ };
+ enum { NDEVS = 4 };
+
+ uint32_t idx = *inout_index;
+ uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent);
+ struct vfs_dirent* ents = (struct vfs_dirent*)buf;
+ uint32_t written = 0;
+
+ while (written < cap) {
+ struct vfs_dirent e;
+ memset(&e, 0, sizeof(e));
+
+ if (idx == 0) {
+ e.d_ino = 1; e.d_type = FS_DIRECTORY; strcpy(e.d_name, ".");
+ } else if (idx == 1) {
+ e.d_ino = 1; e.d_type = FS_DIRECTORY; strcpy(e.d_name, "..");
+ } else {
+ uint32_t di = idx - 2;
+ if (di >= NDEVS) break;
+ e.d_ino = devs[di].ino;
+ e.d_type = devs[di].type;
+ strcpy(e.d_name, devs[di].name);
+ }
+
+ e.d_reclen = (uint16_t)sizeof(e);
+ ents[written] = e;
+ written++;
+ idx++;
+ }
+
+ *inout_index = idx;
+ return (int)(written * (uint32_t)sizeof(struct vfs_dirent));
+}
+
+static int devfs_pts_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len) {
+ (void)node;
+ if (!inout_index || !buf) return -1;
+ if (buf_len < sizeof(struct vfs_dirent)) return -1;
+
+ uint32_t idx = *inout_index;
+ uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent);
+ struct vfs_dirent* ents = (struct vfs_dirent*)buf;
+ uint32_t written = 0;
+
+ while (written < cap) {
+ struct vfs_dirent e;
+ memset(&e, 0, sizeof(e));
+
+ if (idx == 0) {
+ e.d_ino = 5; e.d_type = FS_DIRECTORY; strcpy(e.d_name, ".");
+ } else if (idx == 1) {
+ e.d_ino = 1; e.d_type = FS_DIRECTORY; strcpy(e.d_name, "..");
+ } else if (idx == 2) {
+ e.d_ino = 6; e.d_type = FS_CHARDEVICE; strcpy(e.d_name, "0");
+ } else {
+ break;
+ }
+
+ e.d_reclen = (uint16_t)sizeof(e);
+ ents[written] = e;
+ written++;
+ idx++;
+ }
+
+ *inout_index = idx;
+ return (int)(written * (uint32_t)sizeof(struct vfs_dirent));
+}
+
static void devfs_init_once(void) {
if (g_devfs_inited) return;
g_devfs_inited = 1;
g_dev_root.vfs.open = 0;
g_dev_root.vfs.close = 0;
g_dev_root.vfs.finddir = &devfs_finddir_impl;
+ g_dev_root.vfs.readdir = &devfs_readdir_impl;
memset(&g_dev_null, 0, sizeof(g_dev_null));
strcpy(g_dev_null.name, "null");
g_dev_pts_dir.open = 0;
g_dev_pts_dir.close = 0;
g_dev_pts_dir.finddir = &devfs_pts_finddir_impl;
+ g_dev_pts_dir.readdir = &devfs_pts_readdir_impl;
memset(&g_dev_pts0, 0, sizeof(g_dev_pts0));
strcpy(g_dev_pts0.name, "0");
return total;
}
+static int diskfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len) {
+ if (!node || !inout_index || !buf) return -1;
+ if (node->flags != FS_DIRECTORY) return -1;
+ if (buf_len < sizeof(struct vfs_dirent)) return -1;
+
+ struct diskfs_node* dn = (struct diskfs_node*)node;
+ uint16_t dir_ino = dn->ino;
+
+ // Use diskfs_getdents which fills diskfs_kdirent; convert to vfs_dirent.
+ struct diskfs_kdirent kbuf[8];
+ uint32_t klen = sizeof(kbuf);
+ if (klen > buf_len) klen = buf_len;
+
+ uint32_t idx = *inout_index;
+ int rc = diskfs_getdents(dir_ino, &idx, kbuf, klen);
+ if (rc <= 0) return rc;
+
+ uint32_t nents = (uint32_t)rc / (uint32_t)sizeof(struct diskfs_kdirent);
+ uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent);
+ if (nents > cap) nents = cap;
+
+ struct vfs_dirent* out = (struct vfs_dirent*)buf;
+ for (uint32_t i = 0; i < nents; i++) {
+ memset(&out[i], 0, sizeof(out[i]));
+ out[i].d_ino = kbuf[i].d_ino;
+ out[i].d_reclen = (uint16_t)sizeof(struct vfs_dirent);
+ out[i].d_type = kbuf[i].d_type;
+ diskfs_strlcpy(out[i].d_name, kbuf[i].d_name, sizeof(out[i].d_name));
+ }
+
+ *inout_index = idx;
+ return (int)(nents * (uint32_t)sizeof(struct vfs_dirent));
+}
+
static struct fs_node* diskfs_root_finddir(struct fs_node* node, const char* name) {
struct diskfs_node* parent = (struct diskfs_node*)node;
if (!g_ready) return 0;
dn->vfs.read = 0;
dn->vfs.write = 0;
dn->vfs.finddir = &diskfs_root_finddir;
+ dn->vfs.readdir = &diskfs_readdir_impl;
} else {
dn->vfs.flags = FS_FILE;
dn->vfs.length = sb.inodes[cino].size_bytes;
g_root.vfs.open = 0;
g_root.vfs.close = 0;
g_root.vfs.finddir = &diskfs_root_finddir;
+ g_root.vfs.readdir = &diskfs_readdir_impl;
g_root.ino = 0;
if (g_ready) {
};
static struct fs_node* overlay_finddir_impl(struct fs_node* node, const char* name);
+static int overlay_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len);
static void overlay_str_copy_n(char* dst, size_t dst_sz, const char* src, size_t src_n) {
if (!dst || dst_sz == 0) return;
c->vfs.open = 0;
c->vfs.close = 0;
c->vfs.finddir = (c->vfs.flags == FS_DIRECTORY) ? &overlay_finddir_impl : 0;
+ c->vfs.readdir = (c->vfs.flags == FS_DIRECTORY) ? &overlay_readdir_impl : 0;
if (parent->path[0] == 0) {
c->path[0] = '/';
return &c->vfs;
}
+static int overlay_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len) {
+ if (!node || !inout_index || !buf) return -1;
+ if (node->flags != FS_DIRECTORY) return -1;
+ if (buf_len < sizeof(struct vfs_dirent)) return -1;
+
+ struct overlay_node* dir = (struct overlay_node*)node;
+
+ // Prefer upper layer readdir; fall back to lower.
+ fs_node_t* src = dir->upper ? dir->upper : dir->lower;
+ if (!src || !src->readdir) return 0;
+ return src->readdir(src, inout_index, buf, buf_len);
+}
+
static struct fs_node* overlay_finddir_impl(struct fs_node* node, const char* name) {
if (!node || !name) return 0;
if (node->flags != FS_DIRECTORY) return 0;
root->vfs.open = 0;
root->vfs.close = 0;
root->vfs.finddir = &overlay_finddir_impl;
+ root->vfs.readdir = &overlay_readdir_impl;
root->path[0] = 0;
struct file* f = fd_get(fd);
if (!f || !f->node) return -EBADF;
if (f->node->flags != FS_DIRECTORY) return -ENOTDIR;
-
- // For now only support diskfs dirs (mounted at /disk). We encode diskfs inode as 100+ino.
- if (f->node->inode < 100U) return -ENOSYS;
- uint16_t dir_ino = (uint16_t)(f->node->inode - 100U);
+ if (!f->node->readdir) return -ENOSYS;
uint8_t kbuf[256];
- if (len < (uint32_t)sizeof(kbuf)) {
- // keep behavior simple: require small buffers too
- }
uint32_t klen = len;
if (klen > (uint32_t)sizeof(kbuf)) klen = (uint32_t)sizeof(kbuf);
uint32_t idx = f->offset;
- int rc = diskfs_getdents(dir_ino, &idx, kbuf, klen);
+ int rc = f->node->readdir(f->node, &idx, kbuf, klen);
if (rc < 0) return rc;
if (rc == 0) return 0;
static uint32_t g_tmpfs_next_inode = 1;
static struct fs_node* tmpfs_finddir_impl(struct fs_node* node, const char* name);
+static int tmpfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len);
static uint32_t tmpfs_write_impl(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
static struct tmpfs_node* tmpfs_node_alloc(const char* name, uint32_t flags) {
nd->vfs.open = 0;
nd->vfs.close = 0;
nd->vfs.finddir = &tmpfs_finddir_impl;
+ nd->vfs.readdir = &tmpfs_readdir_impl;
tmpfs_child_add(dir, nd);
return nd;
}
return &child->vfs;
}
+static int tmpfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len) {
+ if (!node || !inout_index || !buf) return -1;
+ if (node->flags != FS_DIRECTORY) return -1;
+ if (buf_len < sizeof(struct vfs_dirent)) return -1;
+
+ struct tmpfs_node* dir = (struct tmpfs_node*)node;
+ uint32_t idx = *inout_index;
+ uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent);
+ struct vfs_dirent* ents = (struct vfs_dirent*)buf;
+ uint32_t written = 0;
+
+ while (written < cap) {
+ struct vfs_dirent e;
+ memset(&e, 0, sizeof(e));
+
+ if (idx == 0) {
+ e.d_ino = node->inode;
+ e.d_type = FS_DIRECTORY;
+ strcpy(e.d_name, ".");
+ } else if (idx == 1) {
+ e.d_ino = dir->parent ? dir->parent->vfs.inode : node->inode;
+ e.d_type = FS_DIRECTORY;
+ strcpy(e.d_name, "..");
+ } else {
+ uint32_t skip = idx - 2;
+ struct tmpfs_node* c = dir->first_child;
+ while (c && skip > 0) { c = c->next_sibling; skip--; }
+ if (!c) break;
+ e.d_ino = c->vfs.inode;
+ e.d_type = (uint8_t)c->vfs.flags;
+ strcpy(e.d_name, c->vfs.name);
+ }
+
+ e.d_reclen = (uint16_t)sizeof(e);
+ ents[written] = e;
+ written++;
+ idx++;
+ }
+
+ *inout_index = idx;
+ return (int)(written * (uint32_t)sizeof(struct vfs_dirent));
+}
+
fs_node_t* tmpfs_create_root(void) {
struct tmpfs_node* root = tmpfs_node_alloc("", FS_DIRECTORY);
if (!root) return NULL;
root->vfs.open = 0;
root->vfs.close = 0;
root->vfs.finddir = &tmpfs_finddir_impl;
+ root->vfs.readdir = &tmpfs_readdir_impl;
return &root->vfs;
}
(uint32_t)(sizeof("[init] rename/rmdir OK\n") - 1));
}
+ // B10: getdents on /dev (devfs) and /tmp (tmpfs)
+ {
+ int devfd = sys_open("/dev", 0);
+ if (devfd < 0) {
+ sys_write(1, "[init] open /dev failed\n",
+ (uint32_t)(sizeof("[init] open /dev failed\n") - 1));
+ sys_exit(1);
+ }
+ char dbuf[256];
+ int dr = sys_getdents(devfd, dbuf, (uint32_t)sizeof(dbuf));
+ (void)sys_close(devfd);
+ if (dr <= 0) {
+ sys_write(1, "[init] getdents /dev failed\n",
+ (uint32_t)(sizeof("[init] getdents /dev failed\n") - 1));
+ sys_exit(1);
+ }
+
+ int tmpfd = sys_open("/tmp", 0);
+ if (tmpfd < 0) {
+ sys_write(1, "[init] open /tmp failed\n",
+ (uint32_t)(sizeof("[init] open /tmp failed\n") - 1));
+ sys_exit(1);
+ }
+ char tbuf[256];
+ int tr = sys_getdents(tmpfd, tbuf, (uint32_t)sizeof(tbuf));
+ (void)sys_close(tmpfd);
+ if (tr <= 0) {
+ sys_write(1, "[init] getdents /tmp failed\n",
+ (uint32_t)(sizeof("[init] getdents /tmp failed\n") - 1));
+ sys_exit(1);
+ }
+
+ sys_write(1, "[init] getdents multi-fs OK\n",
+ (uint32_t)(sizeof("[init] getdents multi-fs OK\n") - 1));
+ }
+
enum { NCHILD = 100 };
int children[NCHILD];
for (int i = 0; i < NCHILD; i++) {