Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
K=kernel
U=user

DIR = example empty

OBJS = \
$K/entry.o \
$K/start.o \
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)

1 change: 1 addition & 0 deletions example/test1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World!
1 change: 1 addition & 0 deletions example/test2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Unrunnable c file
1 change: 1 addition & 0 deletions example/test3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Goodbye World!
93 changes: 91 additions & 2 deletions mkfs/mkfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>

#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)
Expand Down Expand Up @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions test4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
You can delete me
195 changes: 188 additions & 7 deletions user/rm.c
Original file line number Diff line number Diff line change
@@ -1,22 +1,203 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#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
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) {
if (!f) {
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 {
fprintf(2, "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: (%s) does not exist\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");
fprintf(2, "%s", usageMsg);
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
// Read the flag(s)
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\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;
}
}

// Parse the files/directories
for (index = start; index < argc; index++) {
rm(argv[index]);
}

exit(0);
Expand Down