summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kernel/arch/amd64/driver/fsroot.c1
-rw-r--r--src/user/app/tmpfs/tmpfs.c11
-rw-r--r--src/user/bootstrap/tar.c76
-rw-r--r--src/user/lib/fs/dir.c43
-rw-r--r--src/user/lib/fs/misc.c23
5 files changed, 94 insertions, 60 deletions
diff --git a/src/kernel/arch/amd64/driver/fsroot.c b/src/kernel/arch/amd64/driver/fsroot.c
index ea9fa7d..882fe91 100644
--- a/src/kernel/arch/amd64/driver/fsroot.c
+++ b/src/kernel/arch/amd64/driver/fsroot.c
@@ -77,6 +77,7 @@ static int handle(struct vfs_request *req) {
}
case VFSOP_CLOSE: return 0;
+ // TODO getsize for kernel provided directories
case VFSOP_GETSIZE: return -ENOSYS;
default: panic_invalid_state();
diff --git a/src/user/app/tmpfs/tmpfs.c b/src/user/app/tmpfs/tmpfs.c
index 88a9fac..ed3c2e3 100644
--- a/src/user/app/tmpfs/tmpfs.c
+++ b/src/user/app/tmpfs/tmpfs.c
@@ -77,7 +77,6 @@ int main(void) {
} else {
fs_normslice(&res.offset, &res.len, ptr->size, false);
_syscall_fs_respond(ptr->buf + res.offset, res.len, 0);
- break;
}
break;
@@ -119,7 +118,15 @@ int main(void) {
case VFSOP_GETSIZE:
ptr = (void*)res.id;
- _syscall_fs_respond(NULL, ptr->size, 0);
+ if (ptr == &special_root) {
+ struct dirbuild db;
+ dir_start(&db, res.offset, NULL, buflen);
+ for (struct node *iter = root; iter; iter = iter->next)
+ dir_append(&db, iter->name);
+ _syscall_fs_respond(NULL, dir_finish(&db), 0);
+ } else {
+ _syscall_fs_respond(NULL, ptr->size, 0);
+ }
break;
default:
diff --git a/src/user/bootstrap/tar.c b/src/user/bootstrap/tar.c
index 6bd4179..10c3701 100644
--- a/src/user/bootstrap/tar.c
+++ b/src/user/bootstrap/tar.c
@@ -11,6 +11,8 @@
#define BUF_SIZE 64
static void *tar_open(const char *path, int len, void *base, size_t base_len);
+static char tar_type(void *meta);
+static void tar_dirbuild(struct dirbuild *db, const char *meta, void *base, size_t base_len);
static void tar_read(struct fs_wait_response *res, void *base, size_t base_len);
static int tar_size(void *sector);
static int oct_parse(char *str, size_t len);
@@ -35,8 +37,14 @@ void tar_driver(void *base) {
break;
case VFSOP_GETSIZE:
- // TODO works weirdly on directories / the root dir
- _syscall_fs_respond(NULL, tar_size(res.id), 0);
+ if (tar_type(res.id) != '5') {
+ _syscall_fs_respond(NULL, tar_size(res.id), 0);
+ } else {
+ struct dirbuild db;
+ dir_start(&db, res.offset, NULL, 0);
+ tar_dirbuild(&db, res.id, base, ~0);
+ _syscall_fs_respond(NULL, dir_finish(&db), 0);
+ }
break;
default:
@@ -47,6 +55,11 @@ void tar_driver(void *base) {
exit(0);
}
+static char tar_type(void *meta) {
+ if (meta == root_fakemeta) return '5';
+ return *(char*)(meta + 156);
+}
+
static void *tar_open(const char *path, int len, void *base, size_t base_len) {
if (len <= 0) return NULL;
path += 1; // skip the leading slash
@@ -61,51 +74,46 @@ static void *tar_open(const char *path, int len, void *base, size_t base_len) {
return tar_find(path, len, base, base_len);
}
+static void tar_dirbuild(struct dirbuild *db, const char *meta, void *base, size_t base_len) {
+ size_t meta_len = strlen(meta);
+ for (size_t off = 0; off < base_len;) {
+ if (0 != memcmp(base + off + 257, "ustar", 5))
+ break; // not a metadata sector
+
+ /* check if prefix matches */
+ if (0 == memcmp(base + off, meta, meta_len)
+ && *(char*)(base + off + meta_len) != '\0') {
+ char *suffix = base + off + meta_len;
+
+ /* check if the path contains any non-trailing slashes */
+ char *slash = strchr(suffix, '/');
+ if (!slash || slash[1] == '\0') {
+ if (dir_append(db, suffix)) break;
+ }
+ }
+
+ int size = tar_size(base + off);
+ off += 512; // skip this metadata sector
+ off += (size + 511) & ~511; // skip the data sectors
+ }
+}
+
static void tar_read(struct fs_wait_response *res, void *base, size_t base_len) {
void *meta = (void*)res->id;
- char type = *(char*)(meta + 156);
- size_t meta_len;
- int size;
-
static char buf[BUF_SIZE];
// TODO reuse a single buffer for both tar_driver and tar_read
- if (meta == root_fakemeta) type = '5'; /* see comment in tar_open() */
-
- switch (type) {
+ switch (tar_type(meta)) {
case '\0':
case '0': /* normal files */
- size = tar_size(meta);
- fs_normslice(&res->offset, &res->len, size, false);
+ fs_normslice(&res->offset, &res->len, tar_size(meta), false);
_syscall_fs_respond(meta + 512 + res->offset, res->len, 0);
break;
case '5': /* directory */
struct dirbuild db;
dir_start(&db, res->offset, buf, sizeof buf);
-
- meta_len = strlen(meta);
- for (size_t off = 0; off < base_len;) {
- if (0 != memcmp(base + off + 257, "ustar", 5))
- break; // not a metadata sector
-
- /* check if prefix matches */
- if (0 == memcmp(base + off, meta, meta_len)
- && *(char*)(base + off + meta_len) != '\0') {
- char *suffix = base + off + meta_len;
-
- /* check if the path contains any non-trailing slashes */
- char *slash = strchr(suffix, '/');
- if (!slash || slash[1] == '\0') {
- if (dir_append(&db, suffix)) break;
- }
- }
-
- size = tar_size(base + off);
- off += 512; // skip this metadata sector
- off += (size + 511) & ~511; // skip the data sectors
- }
-
+ tar_dirbuild(&db, meta, base, base_len);
_syscall_fs_respond(buf, dir_finish(&db), 0);
break;
diff --git a/src/user/lib/fs/dir.c b/src/user/lib/fs/dir.c
index 802dd61..4235ea6 100644
--- a/src/user/lib/fs/dir.c
+++ b/src/user/lib/fs/dir.c
@@ -33,9 +33,11 @@ bool dir_appendl(struct dirbuild *db, const char *name, size_t len) {
len -= db->offset;
db->offset = 0;
- // TODO no buffer overrun check
- memcpy(db->buf + db->bpos, name, len - 1);
- db->buf[db->bpos + len - 1] = '\0';
+ if (db->buf) {
+ // TODO no buffer overrun check
+ memcpy(db->buf + db->bpos, name, len - 1);
+ db->buf[db->bpos + len - 1] = '\0';
+ }
db->bpos += len;
} else {
db->offset -= len;
@@ -45,26 +47,35 @@ bool dir_appendl(struct dirbuild *db, const char *name, size_t len) {
bool dir_append_from(struct dirbuild *db, handle_t h) {
if (db->error) return true;
+ if (db->buf && db->bpos == db->blen) return false;
- if (db->bpos == db->blen)
- return false;
+ int ret;
+ if (db->buf) {
+ ret = _syscall_read(h, db->buf + db->bpos, db->blen - db->bpos, db->offset);
+ if (ret < 0) {
+ db->error = ret;
+ return true;
+ } else if (ret > 0) {
+ /* not eof */
+ db->offset = 0;
+ db->bpos += ret;
+ return false;
+ } /* else ret == 0, EOF, need getsize */
+ }
- int ret = _syscall_read(h, db->buf + db->bpos, db->blen - db->bpos, db->offset);
+ ret = _syscall_getsize(h);
if (ret < 0) {
db->error = ret;
return true;
}
- if (ret == 0) {
- // TODO no idea how much we've overread
- // this messes up reading bind mounts of multiple directories
- db->error = -ENOSYS;
- return true;
+ if (db->offset < ret) {
+ /* should only occur when !buf, otherwise leaks previous data from buf.
+ * TODO consider impact */
+ db->bpos += ret - db->offset;
+ db->offset = 0;
+ } else {
+ db->offset -= ret;
}
-
- // TODO deduplicate entries
-
- db->offset = 0;
- db->bpos += ret;
return false;
}
diff --git a/src/user/lib/fs/misc.c b/src/user/lib/fs/misc.c
index 54f54fd..16e95e7 100644
--- a/src/user/lib/fs/misc.c
+++ b/src/user/lib/fs/misc.c
@@ -74,9 +74,11 @@ void fs_whitelist(const char **list) {
char *buf = malloc(buf_len);
char *ipath;
bool passthru, inject;
+ struct dirbuild db;
if (!buf) exit(1);
while (!_syscall_fs_wait(buf, buf_len, &res)) {
+ size_t blen;
ipath = res.id;
switch (res.op) {
case VFSOP_OPEN:
@@ -110,16 +112,17 @@ void fs_whitelist(const char **list) {
break;
case VFSOP_READ:
- struct dirbuild db;
- dir_start(&db, res.offset, buf, buf_len);
- size_t blen = strlen(ipath);
+ case VFSOP_GETSIZE:
+ blen = strlen(ipath);
+ char *target = res.op == VFSOP_READ ? buf : NULL;
+ dir_start(&db, res.offset, target, buf_len);
for (const char **iter = list; *iter; iter++) {
// TODO could be precomputed too
size_t len = strlen(*iter); // inefficient, whatever
if (blen < len && !memcmp(ipath, *iter, blen))
dir_appendl(&db, *iter + blen, dir_seglen(*iter + blen));
}
- _syscall_fs_respond(buf, dir_finish(&db), 0);
+ _syscall_fs_respond(target, dir_finish(&db), 0);
break;
case VFSOP_CLOSE:
@@ -175,10 +178,12 @@ void fs_union(const char **list) {
break;
case VFSOP_READ:
+ case VFSOP_GETSIZE:
if (res.capacity > buflen)
res.capacity = buflen;
bool end = false;
- dir_start(&db, res.offset, pre, res.capacity);
+ char *target = res.op == VFSOP_READ ? pre : NULL;
+ dir_start(&db, res.offset, target, res.capacity);
for (size_t i = 0; !end && list[i]; i++) {
const char *prefix = list[i];
size_t prefixlen = strlen(prefix);
@@ -189,7 +194,7 @@ void fs_union(const char **list) {
end = end || dir_append_from(&db, h);
_syscall_close(h);
}
- _syscall_fs_respond(pre, dir_finish(&db), 0);
+ _syscall_fs_respond(target, dir_finish(&db), 0);
break;
default:
@@ -242,13 +247,15 @@ void fs_dir_inject(const char *path) {
break;
case VFSOP_READ:
+ case VFSOP_GETSIZE:
if (res.capacity > buf_len)
res.capacity = buf_len;
- dir_start(&db, res.offset, buf, res.capacity);
+ char *target = res.op == VFSOP_READ ? buf : NULL;
+ dir_start(&db, res.offset, target, res.capacity);
dir_appendl(&db, data->inject, data->inject_len);
if (data->delegate >= 0)
dir_append_from(&db, data->delegate);
- _syscall_fs_respond(buf, dir_finish(&db), 0);
+ _syscall_fs_respond(target, dir_finish(&db), 0);
break;
default: