diff options
Diffstat (limited to 'src/user/app/ext2fs/main.c')
-rw-r--r-- | src/user/app/ext2fs/main.c | 204 |
1 files changed, 136 insertions, 68 deletions
diff --git a/src/user/app/ext2fs/main.c b/src/user/app/ext2fs/main.c index 4fda57c..a5173c3 100644 --- a/src/user/app/ext2fs/main.c +++ b/src/user/app/ext2fs/main.c @@ -3,6 +3,7 @@ #include <camellia/flags.h> #include <camellia/fs/dir.h> #include <camellia/fs/misc.h> +#include <camellia/fsutil.h> #include <camellia/syscalls.h> #include <err.h> #include <errno.h> @@ -18,6 +19,10 @@ struct handle { static int my_read(void *fp, void *buf, size_t len, size_t off); static int my_write(void *fp, const void *buf, size_t len, size_t off); +static void do_open(struct ext2 *fs, handle_t reqh, struct ufs_request *req, char *buf); +static void do_read(struct ext2 *fs, handle_t reqh, struct ufs_request *req, char *buf, size_t buflen); +static void do_write(struct ext2 *fs, handle_t reqh, struct ufs_request *req, char *buf); +static void do_getsize(struct ext2 *fs, handle_t reqh, struct ufs_request *req); static int my_read(void *fp, void *buf, size_t len, size_t off) @@ -43,12 +48,134 @@ my_write(void *fp, const void *buf, size_t len, size_t off) } } +static void +do_open(struct ext2 *fs, handle_t reqh, struct ufs_request *req, char *buf) +{ + bool is_dir = req->len == 0 || buf[req->len-1] == '/'; + uint32_t n = ext2c_walk(fs, buf, req->len); + if (n == 0) { + _syscall_fs_respond(reqh, NULL, -ENOENT, 0); + return; + } + + struct ext2d_inode *inode = ext2_req_inode(fs, n); + if (!inode) { + _syscall_fs_respond(reqh, NULL, -ENOENT, 0); + return; + } + int type = (inode->perms >> 12) & 0xF; + ext2_dropreq(fs, inode, false); + + if ((type == 0x8 && is_dir) || (type == 0x4 && !is_dir)) { + _syscall_fs_respond(reqh, NULL, -ENOENT, 0); + return; + } else if (type != 0x8 && type != 0x4) { + _syscall_fs_respond(reqh, NULL, -ENOSYS, 0); + return; + } + + struct handle *h = malloc(sizeof *h); + if (!h) { + _syscall_fs_respond(reqh, NULL, -1, 0); + return; + } + + h->n = n; + h->dir = is_dir; + _syscall_fs_respond(reqh, h, 0, 0); +} + +static void +do_read(struct ext2 *fs, handle_t reqh, struct ufs_request *req, char *buf, size_t buflen) +{ + struct handle *h = req->id; + if (!h->dir) { + struct ext2d_inode *inode = ext2_req_inode(fs, h->n); + if (!inode) goto err; + fs_normslice(&req->offset, &req->capacity, inode->size_lower, false); + ext2_dropreq(fs, inode, false); + + void *b = ext2_req_file(fs, h->n, &req->capacity, req->offset); + if (!b) goto err; + _syscall_fs_respond(reqh, b, req->capacity, 0); + ext2_dropreq(fs, b, false); + } else { + struct dirbuild db; + char namebuf[257]; + if (req->capacity > buflen) + req->capacity = buflen; + dir_start(&db, req->offset, buf, buflen); + for (struct ext2_diriter iter = {0}; ext2_diriter(&iter, fs, h->n); ) { + if (iter.ent->namelen_lower == 1 && iter.ent->name[0] == '.') { + continue; + } + if (iter.ent->namelen_lower == 2 + && iter.ent->name[0] == '.' + && iter.ent->name[1] == '.') + { + continue; + } + if (iter.ent->type == 2) { /* dir */ + memcpy(namebuf, iter.ent->name, iter.ent->namelen_lower); + namebuf[iter.ent->namelen_lower] = '/'; + dir_appendl(&db, namebuf, iter.ent->namelen_lower + 1); + } else { + dir_appendl(&db, iter.ent->name, iter.ent->namelen_lower); + } + } + _syscall_fs_respond(reqh, buf, dir_finish(&db), 0); + } + return; +err: + _syscall_fs_respond(reqh, NULL, -1, 0); +} + +static void +do_write(struct ext2 *fs, handle_t reqh, struct ufs_request *req, char *buf) +{ + struct handle *h = req->id; + if (h->dir) goto err; + + struct ext2d_inode *inode = ext2_req_inode(fs, h->n); + if (!inode) goto err; + fs_normslice(&req->offset, &req->len, inode->size_lower, true); + if ((req->flags & WRITE_TRUNCATE) || inode->size_lower < req->offset + req->len) { + inode->size_lower = req->offset + req->len; + if (ext2_dropreq(fs, inode, true) < 0) { + goto err; + } + } else { + ext2_dropreq(fs, inode, false); + } + inode = NULL; + + int ret = ext2_write(fs, h->n, buf, req->len, req->offset); + _syscall_fs_respond(reqh, NULL, ret, 0); + return; +err: + _syscall_fs_respond(reqh, NULL, -1, 0); +} + +static void +do_getsize(struct ext2 *fs, handle_t reqh, struct ufs_request *req) { + struct handle *h = req->id; + if (h->dir) goto err; + + struct ext2d_inode *inode = ext2_req_inode(fs, h->n); + if (!inode) goto err; + _syscall_fs_respond(reqh, NULL, inode->size_lower, 0); + ext2_dropreq(fs, inode, false); + return; +err: + _syscall_fs_respond(reqh, NULL, -1, 0); +} + int main(int argc, char **argv) { if (argc < 2) errx(1, "bad usage"); // TODO pread/pwrite for normal handles - FILE *disk = fopen(argv[1], "rw"); + FILE *disk = fopen(argv[1], "r+"); if (!disk) err(1, "couldn't open '%s'", argv[1]); struct e2device *dev = exc_init(my_read, my_write, (void*)disk); @@ -63,77 +190,18 @@ main(int argc, char **argv) handle_t reqh = ufs_wait(buf, buflen, &req); struct handle *h = req.id; if (reqh < 0) break; - switch (req.op) { case VFSOP_OPEN: - bool is_dir = req.len == 0 || buf[req.len-1] == '/'; - uint32_t n = ext2c_walk(fs, buf, req.len); - if (n == 0) { - _syscall_fs_respond(reqh, NULL, -ENOENT, 0); - break; - } - - struct ext2d_inode *inode = ext2_req_inode(fs, n); - if (!inode) { - _syscall_fs_respond(reqh, NULL, -ENOENT, 0); - break; - } - int type = (inode->perms >> 12) & 0xF; - ext2_dropreq(fs, inode, false); - - if ((type == 0x8 && is_dir) || (type == 0x4 && !is_dir)) { - _syscall_fs_respond(reqh, NULL, -ENOENT, 0); - break; - } else if (type != 0x8 && type != 0x4) { - _syscall_fs_respond(reqh, NULL, -ENOSYS, 0); - break; - } - - h = malloc(sizeof *h); - if (!h) { - _syscall_fs_respond(reqh, NULL, -1, 0); - break; - } - - h->n = n; - h->dir = is_dir; - _syscall_fs_respond(reqh, h, 0, 0); + do_open(fs, reqh, &req, buf); break; case VFSOP_READ: - if (!h->dir) { - void *b = ext2_req_file(fs, h->n, &req.capacity, req.offset); - if (b) { - _syscall_fs_respond(reqh, b, req.capacity, 0); - ext2_dropreq(fs, b, false); - } else { - _syscall_fs_respond(reqh, NULL, -1, 0); - } - } else { - struct dirbuild db; - char namebuf[257]; - if (req.capacity > buflen) - req.capacity = buflen; - dir_start(&db, req.offset, buf, buflen); - for (struct ext2_diriter iter = {0}; ext2_diriter(&iter, fs, h->n); ) { - if (iter.ent->namelen_lower == 1 && iter.ent->name[0] == '.') { - continue; - } - if (iter.ent->namelen_lower == 2 - && iter.ent->name[0] == '.' - && iter.ent->name[1] == '.') - { - continue; - } - if (iter.ent->type == 2) { /* dir */ - memcpy(namebuf, iter.ent->name, iter.ent->namelen_lower); - namebuf[iter.ent->namelen_lower] = '/'; - dir_appendl(&db, namebuf, iter.ent->namelen_lower + 1); - } else { - dir_appendl(&db, iter.ent->name, iter.ent->namelen_lower); - } - } - _syscall_fs_respond(reqh, buf, dir_finish(&db), 0); - } + do_read(fs, reqh, &req, buf, buflen); + break; + case VFSOP_WRITE: + do_write(fs, reqh, &req, buf); + break; + case VFSOP_GETSIZE: + do_getsize(fs, reqh, &req); break; case VFSOP_CLOSE: free(h); |