summaryrefslogtreecommitdiff
path: root/src/user/lib/fs
diff options
context:
space:
mode:
authordzwdz2022-08-08 14:33:37 +0200
committerdzwdz2022-08-08 14:33:37 +0200
commit3131d8c2f66bcecb62dfa4c69325951cd9b00706 (patch)
tree595cb0baf29c15d75ffc94d04af71d7ae94517ed /src/user/lib/fs
parentc7af8418c9a2222cde5ab3a6953b31803d0a8ef1 (diff)
fs: getsize() on directories
Diffstat (limited to 'src/user/lib/fs')
-rw-r--r--src/user/lib/fs/dir.c43
-rw-r--r--src/user/lib/fs/misc.c23
2 files changed, 42 insertions, 24 deletions
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: