int diskfs_mkdir(const char* rel_path);
int diskfs_unlink(const char* rel_path);
+// Writes fixed-size dirent records into out buffer.
+// Returns number of bytes written or negative errno.
+int diskfs_getdents(uint16_t dir_ino, uint32_t* inout_index, void* out, uint32_t out_len);
+
#endif
SYSCALL_MKDIR = 28,
SYSCALL_UNLINK = 29,
+
+ SYSCALL_GETDENTS = 30,
};
#endif
uint16_t ino;
};
-static fs_node_t g_root;
+static struct diskfs_node g_root;
static uint32_t g_ready = 0;
static int diskfs_super_store(const struct diskfs_super* sb);
return 0;
}
+struct diskfs_kdirent {
+ uint32_t d_ino;
+ uint16_t d_reclen;
+ uint8_t d_type;
+ char d_name[DISKFS_NAME_MAX];
+};
+
static uint32_t diskfs_read_impl(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
if (!node || !buffer) return 0;
if (node->flags != FS_FILE) return 0;
if (!name || name[0] == 0) return 0;
if (!diskfs_segment_valid(name)) return 0;
- uint16_t parent_ino = 0;
- if (parent) {
- parent_ino = parent->ino;
- }
+ uint16_t parent_ino = parent ? parent->ino : 0;
struct diskfs_super sb;
if (diskfs_super_load(&sb) < 0) return 0;
return diskfs_super_store(&sb);
}
+int diskfs_getdents(uint16_t dir_ino, uint32_t* inout_index, void* out, uint32_t out_len) {
+ if (!inout_index || !out) return -EINVAL;
+ if (!g_ready) return -ENODEV;
+ if (out_len < sizeof(struct diskfs_kdirent)) return -EINVAL;
+
+ struct diskfs_super sb;
+ if (diskfs_super_load(&sb) < 0) return -EIO;
+
+ if (dir_ino >= DISKFS_MAX_INODES) return -ENOENT;
+ if (sb.inodes[dir_ino].type != DISKFS_INODE_DIR) return -ENOTDIR;
+
+ uint32_t idx = *inout_index;
+ uint32_t written = 0;
+ struct diskfs_kdirent* ents = (struct diskfs_kdirent*)out;
+ uint32_t cap = out_len / (uint32_t)sizeof(struct diskfs_kdirent);
+
+ // index 0 => '.' ; index 1 => '..' ; index >=2 => scan inodes
+ while (written < cap) {
+ struct diskfs_kdirent e;
+ memset(&e, 0, sizeof(e));
+
+ if (idx == 0) {
+ e.d_ino = (uint32_t)dir_ino;
+ e.d_type = (uint8_t)DISKFS_INODE_DIR;
+ diskfs_strlcpy(e.d_name, ".", sizeof(e.d_name));
+ } else if (idx == 1) {
+ e.d_ino = (uint32_t)sb.inodes[dir_ino].parent;
+ e.d_type = (uint8_t)DISKFS_INODE_DIR;
+ diskfs_strlcpy(e.d_name, "..", sizeof(e.d_name));
+ } else {
+ uint16_t scan = (uint16_t)(idx - 2);
+ int found = 0;
+ for (; scan < DISKFS_MAX_INODES; scan++) {
+ if (sb.inodes[scan].type == DISKFS_INODE_FREE) continue;
+ if (sb.inodes[scan].parent != dir_ino) continue;
+ if (sb.inodes[scan].name[0] == 0) continue;
+ e.d_ino = (uint32_t)scan;
+ e.d_type = sb.inodes[scan].type;
+ diskfs_strlcpy(e.d_name, sb.inodes[scan].name, sizeof(e.d_name));
+ found = 1;
+ scan++;
+ idx = (uint32_t)scan + 2U;
+ break;
+ }
+ if (!found) break;
+ }
+
+ e.d_reclen = (uint16_t)sizeof(e);
+ ents[written] = e;
+ written++;
+
+ if (idx == 0) idx = 1;
+ else if (idx == 1) idx = 2;
+ }
+
+ *inout_index = idx;
+ return (int)(written * (uint32_t)sizeof(struct diskfs_kdirent));
+}
+
fs_node_t* diskfs_create_root(void) {
if (!g_ready) {
if (ata_pio_init_primary_master() == 0) {
}
memset(&g_root, 0, sizeof(g_root));
- strcpy(g_root.name, "disk");
- g_root.flags = FS_DIRECTORY;
- g_root.inode = 1;
- g_root.length = 0;
- g_root.read = 0;
- g_root.write = 0;
- g_root.open = 0;
- g_root.close = 0;
- g_root.finddir = &diskfs_root_finddir;
+ strcpy(g_root.vfs.name, "disk");
+ g_root.vfs.flags = FS_DIRECTORY;
+ g_root.vfs.inode = 100;
+ g_root.vfs.length = 0;
+ g_root.vfs.read = 0;
+ g_root.vfs.write = 0;
+ g_root.vfs.open = 0;
+ g_root.vfs.close = 0;
+ g_root.vfs.finddir = &diskfs_root_finddir;
+ g_root.ino = 0;
if (g_ready) {
struct diskfs_super sb;
}
}
- return g_ready ? &g_root : 0;
+ return g_ready ? &g_root.vfs : 0;
}
fs_node_t* node = NULL;
if (path[0] == '/' && path[1] == 'd' && path[2] == 'i' && path[3] == 's' && path[4] == 'k' && path[5] == '/') {
- const char* rel = path + 6;
- if (rel[0] == 0) return -ENOENT;
- int rc = diskfs_open_file(rel, flags, &node);
- if (rc < 0) return rc;
+ // With hierarchical diskfs, /disk may contain directories.
+ // Use diskfs_open_file only when creation/truncation is requested.
+ if ((flags & 0x40U) != 0U || (flags & 0x200U) != 0U) {
+ const char* rel = path + 6;
+ if (rel[0] == 0) return -ENOENT;
+ int rc = diskfs_open_file(rel, flags, &node);
+ if (rc < 0) return rc;
+ } else {
+ node = vfs_lookup(path);
+ if (!node) return -ENOENT;
+ }
} else {
node = vfs_lookup(path);
if (!node) return -ENOENT;
return -ENOSYS;
}
+static int syscall_getdents_impl(int fd, void* user_buf, uint32_t len) {
+ if (len == 0) return 0;
+ if (!user_buf) return -EFAULT;
+ if (user_range_ok(user_buf, (size_t)len) == 0) return -EFAULT;
+
+ 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);
+
+ 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);
+ if (rc < 0) return rc;
+ if (rc == 0) return 0;
+
+ if (copy_to_user(user_buf, kbuf, (uint32_t)rc) < 0) return -EFAULT;
+ f->offset = idx;
+ return rc;
+}
+
static int syscall_unlink_impl(const char* user_path) {
if (!user_path) return -EFAULT;
return;
}
+ if (syscall_no == SYSCALL_GETDENTS) {
+ int fd = (int)regs->ebx;
+ void* buf = (void*)regs->ecx;
+ uint32_t len = (uint32_t)regs->edx;
+ regs->eax = (uint32_t)syscall_getdents_impl(fd, buf, len);
+ return;
+ }
+
regs->eax = (uint32_t)-ENOSYS;
}
SYSCALL_MKDIR = 28,
SYSCALL_UNLINK = 29,
+
+ SYSCALL_GETDENTS = 30,
};
enum {
return __syscall_fix(ret);
}
+static int sys_getdents(int fd, void* buf, uint32_t len) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_GETDENTS), "b"(fd), "c"(buf), "d"(len)
+ : "memory"
+ );
+ return __syscall_fix(ret);
+}
+
static void write_int_dec(int v) {
char buf[16];
int i = 0;
}
static int memeq(const void* a, const void* b, uint32_t n) {
- const uint8_t* pa = (const uint8_t*)a;
- const uint8_t* pb = (const uint8_t*)b;
+ const uint8_t* x = (const uint8_t*)a;
+ const uint8_t* y = (const uint8_t*)b;
for (uint32_t i = 0; i < n; i++) {
- if (pa[i] != pb[i]) return 0;
+ if (x[i] != y[i]) return 0;
}
return 1;
}
+static int streq(const char* a, const char* b) {
+ if (!a || !b) return 0;
+ uint32_t i = 0;
+ while (a[i] != 0 && b[i] != 0) {
+ if (a[i] != b[i]) return 0;
+ i++;
+ }
+ return a[i] == b[i];
+}
+
static int sys_sigaction2(int sig, const struct sigaction* act, struct sigaction* oldact) {
int ret;
__asm__ volatile(
// B3: diskfs mkdir/unlink smoke
{
int r = sys_mkdir("/disk/dir");
- if (r < 0 && r != -17) {
- sys_write(1, "[init] mkdir /disk/dir failed\n",
- (uint32_t)(sizeof("[init] mkdir /disk/dir failed\n") - 1));
+ if (r < 0 && errno != 17) {
+ sys_write(1, "[init] mkdir /disk/dir failed errno=", (uint32_t)(sizeof("[init] mkdir /disk/dir failed errno=") - 1));
+ write_int_dec(errno);
+ sys_write(1, "\n", 1);
sys_exit(1);
}
(uint32_t)(sizeof("[init] diskfs mkdir/unlink OK\n") - 1));
}
+ // B4: diskfs getdents smoke
+ {
+ int r = sys_mkdir("/disk/ls");
+ if (r < 0 && errno != 17) {
+ sys_write(1, "[init] mkdir /disk/ls failed errno=", (uint32_t)(sizeof("[init] mkdir /disk/ls failed errno=") - 1));
+ write_int_dec(errno);
+ sys_write(1, "\n", 1);
+ sys_exit(1);
+ }
+
+ int fd = sys_open("/disk/ls/file1", O_CREAT | O_TRUNC);
+ if (fd < 0) {
+ sys_write(1, "[init] create /disk/ls/file1 failed\n",
+ (uint32_t)(sizeof("[init] create /disk/ls/file1 failed\n") - 1));
+ sys_exit(1);
+ }
+ (void)sys_close(fd);
+
+ fd = sys_open("/disk/ls/file2", O_CREAT | O_TRUNC);
+ if (fd < 0) {
+ sys_write(1, "[init] create /disk/ls/file2 failed\n",
+ (uint32_t)(sizeof("[init] create /disk/ls/file2 failed\n") - 1));
+ sys_exit(1);
+ }
+ (void)sys_close(fd);
+
+ int dfd = sys_open("/disk/ls", 0);
+ if (dfd < 0) {
+ sys_write(1, "[init] open dir /disk/ls failed\n",
+ (uint32_t)(sizeof("[init] open dir /disk/ls failed\n") - 1));
+ sys_exit(1);
+ }
+
+ struct {
+ uint32_t d_ino;
+ uint16_t d_reclen;
+ uint8_t d_type;
+ char d_name[24];
+ } ents[8];
+
+ int n = sys_getdents(dfd, ents, (uint32_t)sizeof(ents));
+ (void)sys_close(dfd);
+ if (n <= 0) {
+ sys_write(1, "[init] getdents failed\n",
+ (uint32_t)(sizeof("[init] getdents failed\n") - 1));
+ sys_exit(1);
+ }
+
+ int saw_dot = 0, saw_dotdot = 0, saw_f1 = 0, saw_f2 = 0;
+ int cnt = n / (int)sizeof(ents[0]);
+ for (int i = 0; i < cnt; i++) {
+ if (streq(ents[i].d_name, ".")) saw_dot = 1;
+ else if (streq(ents[i].d_name, "..")) saw_dotdot = 1;
+ else if (streq(ents[i].d_name, "file1")) saw_f1 = 1;
+ else if (streq(ents[i].d_name, "file2")) saw_f2 = 1;
+ }
+
+ if (!saw_dot || !saw_dotdot || !saw_f1 || !saw_f2) {
+ sys_write(1, "[init] getdents verify failed\n",
+ (uint32_t)(sizeof("[init] getdents verify failed\n") - 1));
+ sys_exit(1);
+ }
+
+ sys_write(1, "[init] diskfs getdents OK\n",
+ (uint32_t)(sizeof("[init] diskfs getdents OK\n") - 1));
+ }
+
enum { NCHILD = 100 };
int children[NCHILD];
for (int i = 0; i < NCHILD; i++) {