int diskfs_mkdir(const char* rel_path);
int diskfs_unlink(const char* rel_path);
+int diskfs_rmdir(const char* rel_path);
+int diskfs_rename(const char* old_rel, const char* new_rel);
// Writes fixed-size dirent records into out buffer.
// Returns number of bytes written or negative errno.
#define ERANGE 34
#define ENAMETOOLONG 36
#define ENOSYS 38
+#define ENOTEMPTY 39
#endif
SYSCALL_OPENAT = 36,
SYSCALL_FSTATAT = 37,
SYSCALL_UNLINKAT = 38,
+
+ SYSCALL_RENAME = 39,
+ SYSCALL_RMDIR = 40,
};
#endif
return diskfs_super_store(&sb);
}
+int diskfs_rmdir(const char* rel_path) {
+ if (!g_ready) return -ENODEV;
+ if (!rel_path || rel_path[0] == 0) return -EINVAL;
+
+ struct diskfs_super sb;
+ if (diskfs_super_load(&sb) < 0) return -EIO;
+
+ uint16_t ino = 0;
+ int rc = diskfs_lookup_path(&sb, rel_path, &ino, 0, 0, 0);
+ if (rc < 0) return rc;
+ if (ino == 0) return -EPERM;
+ if (ino >= DISKFS_MAX_INODES) return -EIO;
+ if (sb.inodes[ino].type != DISKFS_INODE_DIR) return -ENOTDIR;
+
+ // Check directory is empty (no children).
+ for (uint16_t i = 0; i < DISKFS_MAX_INODES; i++) {
+ if (sb.inodes[i].type == DISKFS_INODE_FREE) continue;
+ if (sb.inodes[i].parent == ino && i != ino) return -ENOTEMPTY;
+ }
+
+ memset(&sb.inodes[ino], 0, sizeof(sb.inodes[ino]));
+ return diskfs_super_store(&sb);
+}
+
+int diskfs_rename(const char* old_rel, const char* new_rel) {
+ if (!g_ready) return -ENODEV;
+ if (!old_rel || old_rel[0] == 0) return -EINVAL;
+ if (!new_rel || new_rel[0] == 0) return -EINVAL;
+
+ struct diskfs_super sb;
+ if (diskfs_super_load(&sb) < 0) return -EIO;
+
+ uint16_t src_ino = 0;
+ int rc = diskfs_lookup_path(&sb, old_rel, &src_ino, 0, 0, 0);
+ if (rc < 0) return rc;
+ if (src_ino == 0) return -EPERM;
+ if (src_ino >= DISKFS_MAX_INODES) return -EIO;
+
+ // Resolve destination: if it exists, it must be same type or we fail.
+ uint16_t dst_ino = 0;
+ uint16_t dst_parent = 0;
+ char dst_last[DISKFS_NAME_MAX];
+ dst_last[0] = 0;
+ rc = diskfs_lookup_path(&sb, new_rel, &dst_ino, &dst_parent, dst_last, sizeof(dst_last));
+ if (rc == 0) {
+ // Destination exists: if it's a dir and source is file (or vice-versa), error.
+ if (sb.inodes[dst_ino].type != sb.inodes[src_ino].type) return -EINVAL;
+ if (dst_ino == src_ino) return 0; // same inode
+ // Remove destination.
+ memset(&sb.inodes[dst_ino], 0, sizeof(sb.inodes[dst_ino]));
+ } else if (rc == -ENOENT) {
+ // Parent must exist and be a dir.
+ if (dst_parent >= DISKFS_MAX_INODES) return -EIO;
+ if (sb.inodes[dst_parent].type != DISKFS_INODE_DIR) return -ENOTDIR;
+ } else {
+ return rc;
+ }
+
+ // Move: update parent and name.
+ sb.inodes[src_ino].parent = dst_parent;
+ memset(sb.inodes[src_ino].name, 0, sizeof(sb.inodes[src_ino].name));
+ diskfs_strlcpy(sb.inodes[src_ino].name, dst_last, sizeof(sb.inodes[src_ino].name));
+
+ 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;
return syscall_unlink_impl(user_path);
}
+static int syscall_rmdir_impl(const char* user_path) {
+ if (!user_path) return -EFAULT;
+
+ char path[128];
+ int prc = path_resolve_user(user_path, path, sizeof(path));
+ if (prc < 0) return prc;
+
+ 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 -EINVAL;
+ return diskfs_rmdir(rel);
+ }
+
+ return -ENOSYS;
+}
+
+static int syscall_rename_impl(const char* user_old, const char* user_new) {
+ if (!user_old || !user_new) return -EFAULT;
+
+ char oldp[128];
+ char newp[128];
+ int rc = path_resolve_user(user_old, oldp, sizeof(oldp));
+ if (rc < 0) return rc;
+ rc = path_resolve_user(user_new, newp, sizeof(newp));
+ if (rc < 0) return rc;
+
+ // Both must be under /disk/
+ if (oldp[0] == '/' && oldp[1] == 'd' && oldp[2] == 'i' && oldp[3] == 's' && oldp[4] == 'k' && oldp[5] == '/' &&
+ newp[0] == '/' && newp[1] == 'd' && newp[2] == 'i' && newp[3] == 's' && newp[4] == 'k' && newp[5] == '/') {
+ const char* old_rel = oldp + 6;
+ const char* new_rel = newp + 6;
+ if (old_rel[0] == 0 || new_rel[0] == 0) return -EINVAL;
+ return diskfs_rename(old_rel, new_rel);
+ }
+
+ return -ENOSYS;
+}
+
static int syscall_read_impl(int fd, void* user_buf, uint32_t len) {
if (len > 1024 * 1024) return -EINVAL;
if (user_range_ok(user_buf, (size_t)len) == 0) return -EFAULT;
return;
}
+ if (syscall_no == SYSCALL_RENAME) {
+ const char* oldpath = (const char*)regs->ebx;
+ const char* newpath = (const char*)regs->ecx;
+ regs->eax = (uint32_t)syscall_rename_impl(oldpath, newpath);
+ return;
+ }
+
+ if (syscall_no == SYSCALL_RMDIR) {
+ const char* path = (const char*)regs->ebx;
+ regs->eax = (uint32_t)syscall_rmdir_impl(path);
+ return;
+ }
+
regs->eax = (uint32_t)-ENOSYS;
}
SYSCALL_OPENAT = 36,
SYSCALL_FSTATAT = 37,
SYSCALL_UNLINKAT = 38,
+
+ SYSCALL_RENAME = 39,
+ SYSCALL_RMDIR = 40,
};
enum {
return __syscall_fix(ret);
}
+static int sys_rename(const char* oldpath, const char* newpath) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_RENAME), "b"(oldpath), "c"(newpath)
+ : "memory"
+ );
+ return __syscall_fix(ret);
+}
+
+static int sys_rmdir(const char* path) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_RMDIR), "b"(path)
+ : "memory"
+ );
+ return __syscall_fix(ret);
+}
+
static int sys_pipe2(int fds[2], uint32_t flags) {
int ret;
__asm__ volatile(
(uint32_t)(sizeof("[init] *at OK\n") - 1));
}
+ // B9: rename + rmdir smoke
+ {
+ // Create a file, rename it, verify old gone and new exists.
+ int fd = sys_open("/disk/rnold", O_CREAT | O_TRUNC);
+ if (fd < 0) {
+ sys_write(1, "[init] rename: create failed\n",
+ (uint32_t)(sizeof("[init] rename: create failed\n") - 1));
+ sys_exit(1);
+ }
+ (void)sys_write(fd, "RN", 2);
+ (void)sys_close(fd);
+
+ if (sys_rename("/disk/rnold", "/disk/rnnew") < 0) {
+ sys_write(1, "[init] rename failed\n",
+ (uint32_t)(sizeof("[init] rename failed\n") - 1));
+ sys_exit(1);
+ }
+
+ struct stat st;
+ if (sys_stat("/disk/rnold", &st) >= 0) {
+ sys_write(1, "[init] rename: old still exists\n",
+ (uint32_t)(sizeof("[init] rename: old still exists\n") - 1));
+ sys_exit(1);
+ }
+ if (sys_stat("/disk/rnnew", &st) < 0) {
+ sys_write(1, "[init] rename: new not found\n",
+ (uint32_t)(sizeof("[init] rename: new not found\n") - 1));
+ sys_exit(1);
+ }
+
+ (void)sys_unlink("/disk/rnnew");
+
+ // mkdir, then rmdir
+ if (sys_mkdir("/disk/rmtmp") < 0 && errno != 17) {
+ sys_write(1, "[init] rmdir: mkdir failed\n",
+ (uint32_t)(sizeof("[init] rmdir: mkdir failed\n") - 1));
+ sys_exit(1);
+ }
+ if (sys_rmdir("/disk/rmtmp") < 0) {
+ sys_write(1, "[init] rmdir failed\n",
+ (uint32_t)(sizeof("[init] rmdir failed\n") - 1));
+ sys_exit(1);
+ }
+ if (sys_stat("/disk/rmtmp", &st) >= 0) {
+ sys_write(1, "[init] rmdir: dir still exists\n",
+ (uint32_t)(sizeof("[init] rmdir: dir still exists\n") - 1));
+ sys_exit(1);
+ }
+
+ sys_write(1, "[init] rename/rmdir OK\n",
+ (uint32_t)(sizeof("[init] rename/rmdir OK\n") - 1));
+ }
+
enum { NCHILD = 100 };
int children[NCHILD];
for (int i = 0; i < NCHILD; i++) {