First commit of readdir/ls support.
This commit is contained in:
parent
9061f91e74
commit
405868ac8a
@ -53,8 +53,8 @@ typedef struct fs_node {
|
||||
} fs_node_t;
|
||||
|
||||
struct dirent {
|
||||
char name[256]; // The filename.
|
||||
uint32_t ino; // Inode number.
|
||||
char name[256]; // The filename.
|
||||
};
|
||||
|
||||
struct stat {
|
||||
|
@ -51,16 +51,17 @@ DECL_SYSCALL1(exit, int);
|
||||
DECL_SYSCALL1(print, const char *);
|
||||
|
||||
/* Files */
|
||||
DECL_SYSCALL1(close, int);
|
||||
DECL_SYSCALL3(open, const char *, int, int);
|
||||
DECL_SYSCALL3(read, int, char *, int);
|
||||
DECL_SYSCALL3(write, int, char *, int);
|
||||
DECL_SYSCALL2(fstat, int, void *);
|
||||
DECL_SYSCALL1(isatty, int);
|
||||
DECL_SYSCALL2(link, char *, char *);
|
||||
DECL_SYSCALL1(unlink, char *);
|
||||
DECL_SYSCALL3(lseek, int, int, int);
|
||||
DECL_SYSCALL2(stat, const char *, void *);
|
||||
DECL_SYSCALL1(close, int);
|
||||
DECL_SYSCALL3(open, const char *, int, int);
|
||||
DECL_SYSCALL3(read, int, char *, int);
|
||||
DECL_SYSCALL3(readdir, int, int, void *);
|
||||
DECL_SYSCALL3(write, int, char *, int);
|
||||
DECL_SYSCALL2(fstat, int, void *);
|
||||
DECL_SYSCALL1(isatty, int);
|
||||
DECL_SYSCALL2(link, char *, char *);
|
||||
DECL_SYSCALL1(unlink, char *);
|
||||
DECL_SYSCALL3(lseek, int, int, int);
|
||||
DECL_SYSCALL2(stat, const char *, void *);
|
||||
|
||||
/* Process Control */
|
||||
DECL_SYSCALL0(getpid);
|
||||
|
@ -58,6 +58,27 @@ static int read(int fd, char * ptr, int len) {
|
||||
return out;
|
||||
}
|
||||
|
||||
static int readdir(int fd, int index, struct dirent * entry) {
|
||||
if (fd >= (int)current_process->fds.length || fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (current_process->fds.entries[fd] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
validate(entry);
|
||||
fs_node_t * node = current_process->fds.entries[fd];
|
||||
|
||||
struct dirent * kentry = readdir_fs(node, (uint32_t)index);
|
||||
if (!kentry) {
|
||||
free(kentry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(entry, kentry, sizeof(struct dirent));
|
||||
free(kentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write(int fd, char * ptr, int len) {
|
||||
if ((fd == 1 && !current_process->fds.entries[fd]) ||
|
||||
(fd == 2 && !current_process->fds.entries[fd])) {
|
||||
@ -111,7 +132,7 @@ static int open(const char * file, int flags, int mode) {
|
||||
}
|
||||
|
||||
static int close(int fd) {
|
||||
if (fd <= (int)current_process->fds.length || fd < 0) {
|
||||
if (fd >= (int)current_process->fds.length || fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
close_fs(current_process->fds.entries[fd]);
|
||||
@ -334,6 +355,7 @@ static uintptr_t syscalls[] = {
|
||||
(uintptr_t)&setuid, /* 24 */
|
||||
(uintptr_t)&kernel_name_XXX,
|
||||
(uintptr_t)&reboot,
|
||||
(uintptr_t)&readdir,
|
||||
0
|
||||
};
|
||||
uint32_t num_syscalls;
|
||||
|
@ -20,3 +20,5 @@ DEFN_SYSCALL0(getgraphicsdepth, 20)
|
||||
|
||||
DEFN_SYSCALL0(getuid, 23)
|
||||
DEFN_SYSCALL1(setuid, 24, unsigned int)
|
||||
|
||||
DEFN_SYSCALL3(readdir, 27, int, int, void *)
|
||||
|
0
loader/syscall.h
Normal file
0
loader/syscall.h
Normal file
412
userspace/ls.c
Normal file
412
userspace/ls.c
Normal file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* ls
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MIN_COL_SPACING 2
|
||||
|
||||
#define EXE_COLOR "1;32"
|
||||
#define DIR_COLOR "1;34"
|
||||
#define REG_COLOR "0"
|
||||
#define MEDIA_COLOR ""
|
||||
#define SYM_COLOR ""
|
||||
#define BROKEN_COLOR "1;"
|
||||
|
||||
|
||||
/* Shit that belongs as a separate data structure */
|
||||
|
||||
typedef struct node {
|
||||
struct node * next;
|
||||
struct node * prev;
|
||||
void * value;
|
||||
} __attribute__((packed)) node_t;
|
||||
|
||||
typedef struct {
|
||||
node_t * head;
|
||||
node_t * tail;
|
||||
size_t length;
|
||||
} __attribute__((packed)) list_t;
|
||||
|
||||
void list_destroy(list_t * list);
|
||||
void list_free(list_t * list);
|
||||
void list_append(list_t * list, node_t * item);
|
||||
void list_insert(list_t * list, void * item);
|
||||
list_t * list_create();
|
||||
node_t * list_find(list_t * list, void * value);
|
||||
void list_remove(list_t * list, size_t index);
|
||||
void list_delete(list_t * list, node_t * node);
|
||||
node_t * list_pop(list_t * list);
|
||||
node_t * list_dequeue(list_t * list);
|
||||
list_t * list_copy(list_t * original);
|
||||
void list_merge(list_t * target, list_t * source);
|
||||
|
||||
#define foreach(i, list) for (node_t * i = list->head; i != NULL; i = i->next)
|
||||
|
||||
void list_destroy(list_t * list) {
|
||||
/* Free all of the contents of a list */
|
||||
node_t * n = list->head;
|
||||
while (n) {
|
||||
free(n->value);
|
||||
n = n->next;
|
||||
}
|
||||
}
|
||||
|
||||
void list_free(list_t * list) {
|
||||
/* Free the actual structure of a list */
|
||||
node_t * n = list->head;
|
||||
while (n) {
|
||||
node_t * s = n->next;
|
||||
free(n);
|
||||
n = s;
|
||||
}
|
||||
}
|
||||
|
||||
void list_append(list_t * list, node_t * node) {
|
||||
/* Insert a node onto the end of a list */
|
||||
if (!list->tail) {
|
||||
list->head = node;
|
||||
} else {
|
||||
list->tail->next = node;
|
||||
node->prev = list->tail;
|
||||
}
|
||||
list->tail = node;
|
||||
list->length++;
|
||||
}
|
||||
|
||||
void list_insert(list_t * list, void * item) {
|
||||
/* Insert an item into a list */
|
||||
node_t * node = malloc(sizeof(node_t));
|
||||
node->value = item;
|
||||
node->next = NULL;
|
||||
node->prev = NULL;
|
||||
list_append(list, node);
|
||||
}
|
||||
|
||||
list_t * list_create() {
|
||||
/* Create a fresh list */
|
||||
list_t * out = malloc(sizeof(list_t));
|
||||
out->head = NULL;
|
||||
out->tail = NULL;
|
||||
out->length = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
node_t * list_find(list_t * list, void * value) {
|
||||
foreach(item, list) {
|
||||
if (item->value == value) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void list_remove(list_t * list, size_t index) {
|
||||
/* remove index from the list */
|
||||
if (index > list->length) return;
|
||||
size_t i = 0;
|
||||
node_t * n = list->head;
|
||||
while (i < index) {
|
||||
n = n->next;
|
||||
i++;
|
||||
}
|
||||
list_delete(list, n);
|
||||
}
|
||||
|
||||
void list_delete(list_t * list, node_t * node) {
|
||||
/* remove node from the list */
|
||||
if (node == list->head) {
|
||||
list->head = node->next;
|
||||
}
|
||||
if (node == list->tail) {
|
||||
list->tail = node->prev;
|
||||
}
|
||||
if (node->prev) {
|
||||
node->prev->next = node->next;
|
||||
}
|
||||
if (node->next) {
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
list->length--;
|
||||
}
|
||||
|
||||
node_t * list_pop(list_t * list) {
|
||||
/* Remove and return the last value in the list
|
||||
* If you don't need it, you still probably want to free it!
|
||||
* Try free(list_pop(list)); !
|
||||
* */
|
||||
if (!list->tail) return NULL;
|
||||
node_t * out = list->tail;
|
||||
list_delete(list, list->tail);
|
||||
return out;
|
||||
}
|
||||
|
||||
node_t * list_dequeue(list_t * list) {
|
||||
if (!list->head) return NULL;
|
||||
node_t * out = list->head;
|
||||
list_delete(list, list->head);
|
||||
return out;
|
||||
}
|
||||
|
||||
list_t * list_copy(list_t * original) {
|
||||
/* Create a new copy of original */
|
||||
list_t * out = list_create();
|
||||
node_t * node = original->head;
|
||||
while (node) {
|
||||
list_insert(out, node->value);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void list_merge(list_t * target, list_t * source) {
|
||||
/* Destructively merges source into target */
|
||||
if (target->tail) {
|
||||
target->tail->next = source->head;
|
||||
} else {
|
||||
target->head = source->head;
|
||||
}
|
||||
if (source->tail) {
|
||||
target->tail = source->tail;
|
||||
}
|
||||
target->length += source->length;
|
||||
free(source);
|
||||
}
|
||||
|
||||
|
||||
/* Shit that belongs in the clib */
|
||||
|
||||
inline int max (int a, int b) {
|
||||
if (a > b) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
DEFN_SYSCALL3(readdir, 27, int, int, void *)
|
||||
|
||||
/* Should be kept in sync with 'struct dirent' in kernel/include/fs.h */
|
||||
struct dirent {
|
||||
uint32_t inode;
|
||||
char name[256];
|
||||
};
|
||||
|
||||
|
||||
typedef struct DIR {
|
||||
int fd;
|
||||
int cur_entry;
|
||||
} DIR;
|
||||
|
||||
DIR * opendir (const char * dirname) {
|
||||
int fd = open(dirname, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DIR * dir = malloc(sizeof(DIR));
|
||||
dir->fd = fd;
|
||||
dir->cur_entry = -1;
|
||||
return dir;
|
||||
}
|
||||
|
||||
int closedir (DIR * dir) {
|
||||
if (dir && (dir->fd != -1)) {
|
||||
return close(dir->fd);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct dirent * readdir (DIR * dirp) {
|
||||
static struct dirent ent;
|
||||
|
||||
int ret = syscall_readdir(dirp->fd, ++dirp->cur_entry, &ent);
|
||||
if (ret != 0) {
|
||||
memset(&ent, 0, sizeof(struct dirent));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &ent;
|
||||
}
|
||||
|
||||
// TODO: This thing is broken! Oh fuck!
|
||||
/*
|
||||
int readdir_r (DIR *restrict dirp,
|
||||
struct dirent *restrict entry,
|
||||
struct dirent **restrict result) {
|
||||
|
||||
if ((dirp == NULL) || (dirp->fd == -1)) {
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dirent * ent = malloc(sizeof(struct dirent));
|
||||
|
||||
// Find the guy
|
||||
int index = 0;
|
||||
while (1) {
|
||||
int ret = syscall_readdir(dirp->fd, index++, ent);
|
||||
if (ret == -1) {
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/* The program */
|
||||
|
||||
int entcmp (const void * c1, const void * c2) {
|
||||
struct dirent * d1 = *(struct dirent **)c1;
|
||||
struct dirent * d2 = *(struct dirent **)c2;
|
||||
return strcmp(d1->name, d2->name);
|
||||
}
|
||||
|
||||
void print_entry (const char * filename, const char * srcpath, int colwidth) {
|
||||
/* Figure out full relpath */
|
||||
char * relpath = malloc(strlen(srcpath) + strlen(filename) + 2);
|
||||
sprintf(relpath, "%s/%s", srcpath, filename);
|
||||
|
||||
/* Classify file */
|
||||
struct stat statbuf;
|
||||
stat(relpath, &statbuf);
|
||||
free(relpath);
|
||||
|
||||
const char * ansi_color_str;
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
// Directory
|
||||
ansi_color_str = DIR_COLOR;
|
||||
} else if (statbuf.st_mode & 0111) {
|
||||
// Executable
|
||||
ansi_color_str = EXE_COLOR;
|
||||
} else {
|
||||
// Something else
|
||||
ansi_color_str = REG_COLOR;
|
||||
}
|
||||
|
||||
|
||||
/* Print the file name */
|
||||
printf("\033[%sm%s\033[0m", ansi_color_str, filename);
|
||||
|
||||
/* Pad the rest of the column */
|
||||
for (int rem = colwidth - strlen(filename); rem > 0; rem--) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
|
||||
/* Parse arguments */
|
||||
char * p = ".";
|
||||
int explicit_path_set = 0;
|
||||
int show_hidden = 0;
|
||||
|
||||
#if 0
|
||||
if (argc > 1) {
|
||||
int index, c;
|
||||
while ((c = getopt(argc, argv, "a")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
show_hidden = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
p = argv[optind];
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-a") == 0) {
|
||||
show_hidden = 1;
|
||||
} else if (!explicit_path_set) {
|
||||
p = argv[i];
|
||||
explicit_path_set = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Open the directory */
|
||||
DIR * dirp = opendir(p);
|
||||
if (dirp == NULL) {
|
||||
printf("no such directory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read the entries in the directory */
|
||||
list_t * ents_list = list_create();
|
||||
|
||||
struct dirent * ent = readdir(dirp);
|
||||
while (ent != NULL) {
|
||||
if (show_hidden || (ent->name[0] != '.')) {
|
||||
struct dirent * entcpy = malloc(sizeof(struct dirent));
|
||||
memcpy(entcpy, ent, sizeof(struct dirent));
|
||||
list_insert(ents_list, (void *)entcpy);
|
||||
}
|
||||
|
||||
ent = readdir(dirp);
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
/* Now, copy those entries into an array (for sorting) */
|
||||
struct dirent ** ents_array = malloc(sizeof(struct dirent *) * ents_list->length);
|
||||
int index = 0;
|
||||
node_t * node;
|
||||
foreach(node, ents_list) {
|
||||
ents_array[index++] = (struct dirent *)node->value;
|
||||
}
|
||||
list_free(ents_list);
|
||||
int numents = index;
|
||||
|
||||
qsort(ents_array, numents, sizeof(struct dirent *), entcmp);
|
||||
|
||||
/* Determine the gridding dimensions */
|
||||
int ent_max_len = 0;
|
||||
for (int i = 0; i < numents; i++) {
|
||||
ent_max_len = max(ent_max_len, strlen(ents_array[i]->name));
|
||||
}
|
||||
|
||||
const int term_width = 128; // For now, we assume 128
|
||||
|
||||
int col_ext = ent_max_len + MIN_COL_SPACING;
|
||||
int cols = ((term_width - ent_max_len) / col_ext) + 1;
|
||||
#if 0
|
||||
fprintf(stderr, "Printing %dx%d grid (max width: %d)\n", cols, (numents/cols), ent_max_len);
|
||||
#endif
|
||||
|
||||
/* Print the entries */
|
||||
|
||||
// Print rows
|
||||
for (int i = 0; i < numents;) {
|
||||
|
||||
// Print columns on this row
|
||||
print_entry(ents_array[i++]->name, p, ent_max_len);
|
||||
|
||||
for (int j = 0; (i < numents) && (j < (cols-1)); j++) {
|
||||
printf(" ");
|
||||
print_entry(ents_array[i++]->name, p, ent_max_len);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
free(ents_array);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vim: tabstop=4
|
||||
* vim: shiftwidth=4
|
||||
* vim: noexpandtab
|
||||
*/
|
Loading…
Reference in New Issue
Block a user