diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-01-04 18:06:31 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-01-04 18:06:31 +0800 |
| commit | 3886749b1c8d79d4701bf6b8e66249c4e1491648 (patch) | |
| tree | 142e6d9ada3d511663c6c0540196d270c69c0227 /src | |
| parent | a64d25c07b31d57f8706073e11cd774d0880d6dd (diff) | |
| download | lume-3886749b1c8d79d4701bf6b8e66249c4e1491648.tar.gz lume-3886749b1c8d79d4701bf6b8e66249c4e1491648.tar.xz | |
dev(shell): implement basic shell tools
fixed(file-system): fixed read and write bugs
Diffstat (limited to 'src')
| -rw-r--r-- | src/fs/fat32.cc | 32 | ||||
| -rw-r--r-- | src/fs/file.cc | 41 | ||||
| -rw-r--r-- | src/kernel/syscall.cc | 4 | ||||
| -rw-r--r-- | src/user/cat.cc | 48 | ||||
| -rw-r--r-- | src/user/cp.cc | 48 | ||||
| -rw-r--r-- | src/user/grep.cc | 68 | ||||
| -rw-r--r-- | src/user/kill.cc | 23 | ||||
| -rw-r--r-- | src/user/ln.cc | 18 | ||||
| -rw-r--r-- | src/user/mv.cc | 26 | ||||
| -rw-r--r-- | src/user/rm.cc | 24 | ||||
| -rw-r--r-- | src/user/sh.cc | 26 | ||||
| -rw-r--r-- | src/user/touch.cc | 27 | ||||
| -rw-r--r-- | src/user/wc.cc | 56 |
13 files changed, 421 insertions, 20 deletions
diff --git a/src/fs/fat32.cc b/src/fs/fat32.cc index 5c70f5a..17b543c 100644 --- a/src/fs/fat32.cc +++ b/src/fs/fat32.cc @@ -141,8 +141,6 @@ uint32 FAT32FileSystem::next_cluster(uint32 cluster) uint32 ent_offset = fat_offset % 512; // block = sector / 2 - // offset in block = (sector % 2) * 512 + ent_offset - struct Buf *b = BufferCache::bread(0, fat_sector / 2); uint32 block_offset = (fat_sector % 2) * 512 + ent_offset; @@ -177,6 +175,20 @@ int FAT32Inode::read(char *dst, uint32 off, uint32 n, int isUser) if (first_clus == 0) return 0; + // [FIX] 只有非目录文件才检查 size 边界 + // 目录文件 size 可能为 0,应允许读取直到簇链结束 + if (type != T_DIR) + { + if (off >= size) + { + return 0; + } + if (off + n > size) + { + n = size - off; + } + } + uint32 tot = 0; uint32 clus = first_clus; uint32 clus_sz = fs->bytes_per_cluster; @@ -303,7 +315,7 @@ uint32 FAT32FileSystem::alloc_cluster() uint32 current_fat_sec = fat_start_sector + i; struct Buf *b = BufferCache::bread(0, current_fat_sec / 2); uint32 *table = (uint32 *)(b->data + (current_fat_sec % 2) * 512); - for(uint32 j = 0; j < fat_entries_per_sector; j++) + for (uint32 j = 0; j < fat_entries_per_sector; j++) { if (i == 0 && j < 2) continue; @@ -359,7 +371,6 @@ void FAT32FileSystem::free_cluster_chain(uint32 cluster) cluster = next; } - } void FAT32Inode::update() @@ -654,7 +665,9 @@ int FAT32Inode::unlink(const char *name) uint32_t clus = first_clus; bool found = false; - struct Buf *target_buf = nullptr; + + // [FIX] Deadlock prevention: Do not hold buffer while looking up inode + uint32_t target_block = 0; uint32_t target_offset = 0; struct FAT32_DirEnt de; @@ -681,16 +694,16 @@ int FAT32Inode::unlink(const char *name) if (match_name(de.name, name)) { - target_buf = b; + target_block = (sec + i) / 2; target_offset = ((sec + i) % 2) * 512 + off; found = true; break; } } + BufferCache::brelse(b); // Always release buffer if (found) break; - BufferCache::brelse(b); } if (found) @@ -701,7 +714,7 @@ int FAT32Inode::unlink(const char *name) return -1; } - if (found && target_buf) + if (found) { Inode *target_ip = lookup(name); if (target_ip) @@ -710,7 +723,6 @@ int FAT32Inode::unlink(const char *name) if (target_ip->type == T_DIR) { VFS::iunlockput(target_ip); - BufferCache::brelse(target_buf); return -1; } @@ -719,6 +731,8 @@ int FAT32Inode::unlink(const char *name) VFS::iunlockput(target_ip); } + // Re-read buffer to mark deletion + struct Buf *target_buf = BufferCache::bread(dev, target_block); uint8_t *ptr = (uint8_t *)target_buf->data + target_offset; *ptr = 0xE5; diff --git a/src/fs/file.cc b/src/fs/file.cc index 623b535..9f12dc1 100644 --- a/src/fs/file.cc +++ b/src/fs/file.cc @@ -217,6 +217,16 @@ namespace FileTable if (f->type == FD_INODE) { VFS::ilock(f->ip); + + if (f->ip->type == T_DEVICE) + { + if (f->ip->major == 1) + { + VFS::iunlock(f->ip); + return Drivers::console_read(addr, n); + } + } + int r = f->ip->read((char*)addr, f->off, n, 1); if(r > 0) { @@ -240,6 +250,37 @@ namespace FileTable if (f->type == FD_INODE) { VFS::ilock(f->ip); + + if (f->ip->type == T_DEVICE) + { + if (f->ip->major == 1) // Console + { + VFS::iunlock(f->ip); + struct Proc *proc = myproc(); + constexpr int MAX_WRITE_BUF = 128; + char buf[MAX_WRITE_BUF]; + int i = 0; + while (i < n) + { + int len = n - i; + if (len > MAX_WRITE_BUF) + len = MAX_WRITE_BUF; + + if (VM::copyin(proc->pagetable, buf, addr + i, static_cast<uint64>(len)) < 0) + { + return -1; + } + + for (int j = 0; j < len; j++) + { + Drivers::uart_putc(buf[j]); + } + i += len; + } + return n; + } + } + int r = f->ip->write((char *)addr, f->off, n, 1); if (r > 0) { diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc index 259a5e6..9f88649 100644 --- a/src/kernel/syscall.cc +++ b/src/kernel/syscall.cc @@ -503,7 +503,9 @@ static uint64_t sys_read() // get param: fd, buf, len if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argint(1, (int *)&p) < 0) return -1; - + + p = argraw(1); + struct Proc* proc = myproc(); if (fd == 0 && proc->ofile[fd] == nullptr) { diff --git a/src/user/cat.cc b/src/user/cat.cc new file mode 100644 index 0000000..67feb1c --- /dev/null +++ b/src/user/cat.cc @@ -0,0 +1,48 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "ulib/string.h" +#include "user/user.h" +#include "common/fcntl.h" + +char buf[512]; + +void cat(int fd) +{ + int n; + while ((n = read(fd, buf, sizeof(buf))) > 0) + { + if (write(1, buf, n) != n) + { + printf("cat: write error\n"); + exit(1); + } + } + if (n < 0) + { + printf("cat: read error\n"); + exit(1); + } +} + +int main(int argc, char *argv[]) +{ + int fd, i; + + if (argc <= 1) + { + cat(0); + exit(0); + } + + for (i = 1; i < argc; i++) + { + if ((fd = open(argv[i], O_RDONLY)) < 0) + { + printf("cat: cannot open %s\n", argv[i]); + exit(1); + } + cat(fd); + close(fd); + } + exit(0); +}
\ No newline at end of file diff --git a/src/user/cp.cc b/src/user/cp.cc new file mode 100644 index 0000000..9f13bef --- /dev/null +++ b/src/user/cp.cc @@ -0,0 +1,48 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "user/user.h" +#include "common/fcntl.h" + +char buf[512]; + +int main(int argc, char *argv[]) +{ + int fd_src, fd_dst, n; + + if (argc != 3) + { + printf("Usage: cp src dst\n"); + exit(1); + } + + if ((fd_src = open(argv[1], O_RDONLY)) < 0) + { + printf("cp: cannot open source %s\n", argv[1]); + exit(1); + } + + if ((fd_dst = open(argv[2], O_WRONLY | O_CREATE | O_TRUNC)) < 0) + { + printf("cp: cannot create destination %s\n", argv[2]); + close(fd_src); + exit(1); + } + + while ((n = read(fd_src, buf, sizeof(buf))) > 0) + { + if (write(fd_dst, buf, n) != n) + { + printf("cp: write error\n"); + exit(1); + } + } + + if (n < 0) + { + printf("cp: read error\n"); + } + + close(fd_src); + close(fd_dst); + exit(0); +}
\ No newline at end of file diff --git a/src/user/grep.cc b/src/user/grep.cc new file mode 100644 index 0000000..5ed61b4 --- /dev/null +++ b/src/user/grep.cc @@ -0,0 +1,68 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "ulib/string.h" +#include "user/user.h" +#include "common/fcntl.h" + +char buf[1024]; + +void grep(char *pattern, int fd) +{ + int n, m; + char *p, *q; + + m = 0; + while ((n = read(fd, buf + m, sizeof(buf) - m - 1)) > 0) + { + m += n; + buf[m] = '\0'; + p = buf; + while ((q = strchr(p, '\n')) != 0) + { + *q = 0; + if (strstr(p, pattern) != 0) + { + printf("%s\n", p); + } + p = q + 1; + } + if (p == buf) + m = 0; + if (m > 0) + { + m -= p - buf; + memmove(buf, p, m); + } + } +} + +int main(int argc, char *argv[]) +{ + int fd, i; + char *pattern; + + if (argc < 2) + { + printf("Usage: grep pattern [file...]\n"); + exit(1); + } + pattern = argv[1]; + + if (argc == 2) + { + grep(pattern, 0); // stdin + exit(0); + } + + for (i = 2; i < argc; i++) + { + if ((fd = open(argv[i], O_RDONLY)) < 0) + { + printf("grep: cannot open %s\n", argv[i]); + exit(1); + } + grep(pattern, fd); + close(fd); + } + exit(0); +}
\ No newline at end of file diff --git a/src/user/kill.cc b/src/user/kill.cc new file mode 100644 index 0000000..18b7f02 --- /dev/null +++ b/src/user/kill.cc @@ -0,0 +1,23 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "user/user.h" + +int main(int argc, char *argv[]) +{ + int i; + + if (argc < 2) + { + printf("Usage: kill pid...\n"); + exit(1); + } + for (i = 1; i < argc; i++) + { + int pid = atoi(argv[i]); + if (kill(pid) < 0) + { + printf("kill: failed to kill %d\n", pid); + } + } + exit(0); +}
\ No newline at end of file diff --git a/src/user/ln.cc b/src/user/ln.cc new file mode 100644 index 0000000..2370fdc --- /dev/null +++ b/src/user/ln.cc @@ -0,0 +1,18 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "user/user.h" + +int main(int argc, char *argv[]) +{ + if (argc != 3) + { + printf("Usage: ln old new\n"); + exit(1); + } + if (link(argv[1], argv[2]) < 0) + { + printf("link %s %s failed\n", argv[1], argv[2]); + exit(1); + } + exit(0); +}
\ No newline at end of file diff --git a/src/user/mv.cc b/src/user/mv.cc new file mode 100644 index 0000000..2d30f01 --- /dev/null +++ b/src/user/mv.cc @@ -0,0 +1,26 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "user/user.h" + +int main(int argc, char *argv[]) +{ + if (argc != 3) + { + printf("Usage: mv old new\n"); + exit(1); + } + + if (link(argv[1], argv[2]) < 0) + { + printf("mv: failed to link %s to %s\n", argv[1], argv[2]); + exit(1); + } + + if (unlink(argv[1]) < 0) + { + printf("mv: failed to unlink %s\n", argv[1]); + exit(1); + } + + exit(0); +}
\ No newline at end of file diff --git a/src/user/rm.cc b/src/user/rm.cc new file mode 100644 index 0000000..82b04c5 --- /dev/null +++ b/src/user/rm.cc @@ -0,0 +1,24 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "user/user.h" + +int main(int argc, char *argv[]) +{ + int i; + + if (argc < 2) + { + printf("Usage: rm files...\n"); + exit(1); + } + + for (i = 1; i < argc; i++) + { + if (unlink(argv[i]) < 0) + { + printf("rm: %s failed to delete\n", argv[i]); + exit(1); + } + } + exit(0); +}
\ No newline at end of file diff --git a/src/user/sh.cc b/src/user/sh.cc index b4122f7..760f29e 100644 --- a/src/user/sh.cc +++ b/src/user/sh.cc @@ -67,11 +67,26 @@ struct RedirCommand : public Command void run() override { close(fd); - if (open(file, mode) < 0) + + int newfd = open(file, mode); + + if (newfd < 0) { printf("open %s failed\n", file); exit(1); } + + if (newfd != fd) + { + + if (dup(newfd) != fd) + { + printf("Redirection failed: could not move fd %d to %d\n", newfd, fd); + exit(1); + } + close(newfd); + } + sub_cmd->run(); } }; @@ -348,15 +363,6 @@ int main() { static char buf[100]; - // int fd; - // while ((fd = open("console", O_RDWR)) >= 0) - // { - // if (fd >= 3) - // { - // close(fd); - // break; - // } - // } printf(ANSI_GREEN"\n[Lume Shell] Welcome! \n"ANSI_RESET); printf(ANSI_YELLOW "[Lume Shell] Start your journey of exploration!"ANSI_RESET); diff --git a/src/user/touch.cc b/src/user/touch.cc new file mode 100644 index 0000000..b978f52 --- /dev/null +++ b/src/user/touch.cc @@ -0,0 +1,27 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "user/user.h" +#include "common/fcntl.h" + +int main(int argc, char *argv[]) +{ + int i, fd; + + if (argc < 2) + { + printf("Usage: touch files...\n"); + exit(1); + } + + for (i = 1; i < argc; i++) + { + fd = open(argv[i], O_CREATE | O_RDWR); + if (fd < 0) + { + printf("touch: cannot touch %s\n", argv[i]); + exit(1); + } + close(fd); + } + exit(0); +}
\ No newline at end of file diff --git a/src/user/wc.cc b/src/user/wc.cc new file mode 100644 index 0000000..654aac2 --- /dev/null +++ b/src/user/wc.cc @@ -0,0 +1,56 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "ulib/string.h" +#include "user/user.h" +#include "common/fcntl.h" + +char buf[512]; + +void wc(int fd, char *name) +{ + int i, n; + int l, w, c, inword; + + l = w = c = 0; + inword = 0; + while ((n = read(fd, buf, sizeof(buf))) > 0) + { + for (i = 0; i < n; i++) + { + c++; + if (buf[i] == '\n') + l++; + if (strchr(" \r\t\n\v", buf[i])) + inword = 0; + else if (!inword) + { + w++; + inword = 1; + } + } + } + printf("%d %d %d %s\n", l, w, c, name); +} + +int main(int argc, char *argv[]) +{ + int fd, i; + + if (argc <= 1) + { + wc(0, ""); + exit(0); + } + + for (i = 1; i < argc; i++) + { + if ((fd = open(argv[i], O_RDONLY)) < 0) + { + printf("wc: cannot open %s\n", argv[i]); + exit(1); + } + wc(fd, argv[i]); + close(fd); + } + exit(0); +}
\ No newline at end of file |
