From f2d7467c3992d57aa9b69753a8e67c2d81e450f9 Mon Sep 17 00:00:00 2001 From: Andy Wu Date: Tue, 24 Sep 2024 00:44:58 -0700 Subject: [PATCH 1/3] Added flags to rm command --- user/rm.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 170 insertions(+), 6 deletions(-) diff --git a/user/rm.c b/user/rm.c index 26b8f1f..20237a6 100644 --- a/user/rm.c +++ b/user/rm.c @@ -1,22 +1,186 @@ #include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" +#include "kernel/fs.h" + +#define MAX_PATH 512 + +// Boolean variables for flag processing, defaulted to false +int v, r, f, i, d = 0; + +/* + Deletes files/directories. Can verbose + + @param path path to delete +*/ +void +delete(char* path) +{ + if(unlink(path) < 0) { + fprintf(2, "rm: %s failed to delete\n", path); + exit(1); + } + + if (v) { + printf("rm: deleted %s\n", path); + } +} + +/* + Helper function to concat two string paths together to a destination string + + @param dest destination string + @param path1 first path + @param path2 second path +*/ +void +concat_paths(char* dest, char* path1, char* path2) { + int i = 0, j = 0; + + while (path1[i] != '\0' && i < MAX_PATH - 1) { + dest[i] = path1[i]; + i++; + } + + if (i > 0 && dest[i-1] != '/') { + dest[i] = '/'; + i++; + } + + while (path2[j] != '\0' && i < MAX_PATH - 1) { + dest[i] = path2[j]; + i++; + j++; + } + + dest[i] = '\0'; +} + +/* + Main function of rm. Checks for flags and appropriately rm + files/directories using delete(). Possible flags include: + -r recursive + -f force + -i interactive + -d empty directory + + @param path path to process +*/ +void +rm(char *path) +{ + // Cannot rm an empty directory recursively + if (d && r) { + fprintf(2, "rm: Cannot use flags '-d' and '-r' together.\n"); + exit(1); + } + + // Cannot rm with interactive and force + if (i && f) { + fprintf(2, "rm: Cannot use flags '-i' and '-f' together.\n"); + exit(1); + } + + // Interactive + if (i) { + while (1) { + printf("rm: Delete '%s'?\nEnter [y] for yes or [n] for no\n", path); + char answer[32]; + read(0, answer, 32 - 1); + answer[31] = '\0'; + if (answer[0] == 'y') { + break; + } else if (answer[0] == 'n') { + return; + } else { + printf("Invalid answer.\n"); + } + } + } + + // Empty directory, just delete it + if (d) { + delete(path); + return; + } + + // Directory processing + struct stat st; + if (stat(path, &st) < 0) { + fprintf(2, "rm: stat(%s) failed\n", path); + } + if (st.type == T_DIR) { + // Recursively delete all files/directories + if (r) { + int dir = open(path, 0); + if (dir < 0) { + fprintf(2, "rm: open(%s) error\n", path); + exit(1); + } + struct dirent de; + int n; + while ((n = read(dir, &de, sizeof(de))) > 0) { + if (de.inum == 0 || strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0) { + continue; // Skip empty entries and . or .. + } + char entry[512]; + concat_paths(entry, path, de.name); + rm(entry); + } + close(dir); + } + } + delete(path); +} + int main(int argc, char *argv[]) { - int i; + int index; + int start = 1; if(argc < 2){ fprintf(2, "Usage: rm files...\n"); exit(1); } - for(i = 1; i < argc; i++){ - if(unlink(argv[i]) < 0){ - fprintf(2, "rm: %s failed to delete\n", argv[i]); - break; - } + // Parse the flags + for (index = 1; index < argc; index++) { + if (argv[index][0] == '-') { // Check if argv is even a flag + char *flag = argv[index] + 1; + while (*flag) { + switch (*flag) { + case 'r': + r = 1; + break; + case 'v': + v = 1; + break; + case 'f': + f = 1; + break; + case 'i': + i = 1; + break; + case 'd': + d = 1; + break; + default: + fprintf(2, "rm: invalid flag '%s'\n", *flag); + exit(1); + } + flag++; + } + } else { // Not a flag + start = index; + break; + } + } + + // Parse the files/directories + for (index = start; index < argc; index++) { + rm(argv[index]); } exit(0); From ec73d1acaa1fee34f2cf40719dfb70a504aae10a Mon Sep 17 00:00:00 2001 From: Andy Wu Date: Tue, 24 Sep 2024 10:55:30 -0700 Subject: [PATCH 2/3] Added support for -f flag --- user/rm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/user/rm.c b/user/rm.c index 20237a6..2b802fa 100644 --- a/user/rm.c +++ b/user/rm.c @@ -17,8 +17,10 @@ void delete(char* path) { if(unlink(path) < 0) { - fprintf(2, "rm: %s failed to delete\n", path); - exit(1); + if (!f) { + fprintf(2, "rm: %s failed to delete\n", path); + exit(1); + } } if (v) { From 7243f3b8d2dcb02f30e814db81c2d0233fef45f1 Mon Sep 17 00:00:00 2001 From: Andy Wu Date: Sun, 6 Oct 2024 17:32:20 -0700 Subject: [PATCH 3/3] Addressing CR issues, adding test directories/files --- Makefile | 7 ++-- example/test1.txt | 1 + example/test2.c | 1 + example/test3.txt | 1 + mkfs/mkfs.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++- test4.txt | 1 + user/rm.c | 23 ++++++++++-- 7 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 example/test1.txt create mode 100644 example/test2.c create mode 100644 example/test3.txt create mode 100644 test4.txt diff --git a/Makefile b/Makefile index 2584e4a..62960c4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ K=kernel U=user +DIR = example empty + OBJS = \ $K/entry.o \ $K/start.o \ @@ -133,8 +135,8 @@ UPROGS=\ $U/_wc\ $U/_zombie\ -fs.img: mkfs/mkfs README.md $(UPROGS) - mkfs/mkfs fs.img README.md $(UPROGS) +fs.img: mkfs/mkfs README.md $(UPROGS) $(DIR) test4.txt + mkfs/mkfs fs.img README.md $(UPROGS) $(DIR) test4.txt -include kernel/*.d user/*.d @@ -170,4 +172,3 @@ qemu: $K/kernel fs.img qemu-gdb: $K/kernel .gdbinit fs.img @echo "*** Now run 'gdb' in another window." 1>&2 $(QEMU) $(QEMUOPTS) -S $(QEMUGDB) - diff --git a/example/test1.txt b/example/test1.txt new file mode 100644 index 0000000..980a0d5 --- /dev/null +++ b/example/test1.txt @@ -0,0 +1 @@ +Hello World! diff --git a/example/test2.c b/example/test2.c new file mode 100644 index 0000000..0acb6df --- /dev/null +++ b/example/test2.c @@ -0,0 +1 @@ +Unrunnable c file diff --git a/example/test3.txt b/example/test3.txt new file mode 100644 index 0000000..1ce3f81 --- /dev/null +++ b/example/test3.txt @@ -0,0 +1 @@ +Goodbye World! diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 1ec326b..9bbc090 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -4,12 +4,18 @@ #include #include #include +#include +#include +#include +#define dirent xv6_dirent #define stat xv6_stat // avoid clash with host struct stat #include "kernel/types.h" #include "kernel/fs.h" #include "kernel/stat.h" #include "kernel/param.h" +#undef dirent +#undef stat #ifndef static_assert #define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0) @@ -65,12 +71,88 @@ xint(uint x) return y; } +void +add_file(int parent_fd, uint parentino, char *filename) +{ + uint inum; + int fd; + char buf[BSIZE]; + struct xv6_dirent de; + + if((fd = openat(parent_fd, filename, 0)) < 0) + die(filename); + + inum = ialloc(T_FILE); + + bzero(&de, sizeof(de)); + de.inum = xshort(inum); + strncpy(de.name, filename, DIRSIZ); + iappend(parentino, &de, sizeof(de)); + + ssize_t cc; + while((cc = read(fd, buf, sizeof(buf))) > 0) + iappend(inum, buf, cc); + + close(fd); +} + +uint +add_dir(int level, int parent_fd, uint parentino, char *dirname) +{ + struct xv6_dirent de; + uint dino = ialloc(T_DIR); + bzero(&de, sizeof(de)); + de.inum = xshort(dino); + strcpy(de.name, dirname); + iappend(parentino, &de, sizeof(de)); + + bzero(&de, sizeof(de)); + de.inum = xshort(dino); + strcpy(de.name, "."); + iappend(dino, &de, sizeof(de)); + + bzero(&de, sizeof(de)); + de.inum = xshort(parentino); + strcpy(de.name, ".."); + iappend(dino, &de, sizeof(de)); + + int dir_fd = -1; + if ((dir_fd = openat(parent_fd, dirname, O_RDONLY)) == -1) { + perror("open"); + return dino; + } + + DIR *d = fdopendir(dir_fd); + if (d == NULL) { + perror("fdopendir"); + return dino; + } + + struct dirent *e; + while ((e = readdir(d)) != NULL) { + if (e->d_name[0] == '.') { + continue; + } + + if (e->d_type == DT_REG) { + printf("%*s+ %s\n", level * 2, "", e->d_name); + add_file(dir_fd, dino, e->d_name); + } else if (e->d_type == DT_DIR) { + printf("%*s+ /%s\n", level * 2, "", e->d_name); + add_dir(level + 1, dir_fd, dino, e->d_name); + } + } + close(dir_fd); + + return dino; +} + int main(int argc, char *argv[]) { int i, cc, fd; uint rootino, inum, off; - struct dirent de; + struct xv6_dirent de; char buf[BSIZE]; struct dinode din; @@ -83,7 +165,7 @@ main(int argc, char *argv[]) } assert((BSIZE % sizeof(struct dinode)) == 0); - assert((BSIZE % sizeof(struct dirent)) == 0); + assert((BSIZE % sizeof(struct xv6_dirent)) == 0); fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); if(fsfd < 0) @@ -128,6 +210,13 @@ main(int argc, char *argv[]) iappend(rootino, &de, sizeof(de)); for(i = 2; i < argc; i++){ + struct stat sb; + stat(argv[i], &sb); + if (S_ISDIR(sb.st_mode)) { + add_dir(0, AT_FDCWD, rootino, argv[i]); + continue; + } + // get rid of "user/" char *shortname; if(strncmp(argv[i], "user/", 5) == 0) diff --git a/test4.txt b/test4.txt new file mode 100644 index 0000000..46d9f10 --- /dev/null +++ b/test4.txt @@ -0,0 +1 @@ +You can delete me diff --git a/user/rm.c b/user/rm.c index 2b802fa..ed890a3 100644 --- a/user/rm.c +++ b/user/rm.c @@ -3,6 +3,15 @@ #include "user/user.h" #include "kernel/fs.h" +const char *usageMsg = "Usage: rm file/directory.\n" +"Possible flags: -v, -r, -f, -i, -d\n" +"-v file/directory\n" +"-r directory\n" +"-f file/directory\n" +"-i file/directory\n" +"-d directory\n"; + + #define MAX_PATH 512 // Boolean variables for flag processing, defaulted to false @@ -95,7 +104,7 @@ rm(char *path) } else if (answer[0] == 'n') { return; } else { - printf("Invalid answer.\n"); + fprintf(2, "Invalid answer.\n"); } } } @@ -109,7 +118,7 @@ rm(char *path) // Directory processing struct stat st; if (stat(path, &st) < 0) { - fprintf(2, "rm: stat(%s) failed\n", path); + fprintf(2, "rm: (%s) does not exist\n", path); } if (st.type == T_DIR) { // Recursively delete all files/directories @@ -143,13 +152,14 @@ main(int argc, char *argv[]) int start = 1; if(argc < 2){ - fprintf(2, "Usage: rm files...\n"); + fprintf(2, "%s", usageMsg); exit(1); } // Parse the flags for (index = 1; index < argc; index++) { if (argv[index][0] == '-') { // Check if argv is even a flag + // Read the flag(s) char *flag = argv[index] + 1; while (*flag) { switch (*flag) { @@ -169,11 +179,16 @@ main(int argc, char *argv[]) d = 1; break; default: - fprintf(2, "rm: invalid flag '%s'\n", *flag); + fprintf(2, "rm: invalid flag\n"); exit(1); } flag++; } + // Check if there is path after flag + if (index + 1 >= argc) { + fprintf(2, "No path found after flag.\n"); + exit(1); + } } else { // Not a flag start = index; break;