diff --git a/sys/bootstrap/tar.c b/sys/bootstrap/tar.c index f447404..bc71efe 100644 --- a/sys/bootstrap/tar.c +++ b/sys/bootstrap/tar.c @@ -11,6 +11,7 @@ #include #include #include +#include #include struct tar_superblock { @@ -148,6 +149,24 @@ static struct tar_entry *entry_get_child( return NULL; } +static struct tar_entry *entry_get_child_at(struct tar_entry *entry, size_t at) +{ + struct queue_entry *cur = queue_first(&entry->e_children); + while (cur) { + struct tar_entry *child + = QUEUE_CONTAINER(struct tar_entry, e_entry, cur); + + if (at == 0) { + return child; + } + + at--; + cur = queue_next(cur); + } + + return NULL; +} + static const struct fs_dentry_ops dentry_ops = {}; static enum fs_status dir_lookup( @@ -189,7 +208,7 @@ static enum fs_status file_read( char *src = (char *)entry->e_data + offset; size_t w; - xpc_buffer_write(buf, src, count, &w); + xpc_buffer_write(buf, 0, src, count, &w); offset += w; *seek = offset; @@ -197,10 +216,66 @@ static enum fs_status file_read( return FS_SUCCESS; } +static enum fs_status dir_readdir( + struct fs_file *f, + xpc_buffer_t *out, + off_t *seek) +{ + off_t offset = *seek; + struct tar_entry *entry = entry_from_inode(fs_file_get_inode(f)); + if (!entry) { + return FS_ERR_BAD_STATE; + } + + size_t bytes_written = 0; + size_t available = xpc_buffer_capacity(out); + + while (1) { + struct tar_entry *child = entry_get_child_at(entry, offset); + if (!child) { + break; + } + + struct dentry dent = {0}; + + size_t name_len = strlen(child->e_dentry.d_name); + size_t to_write + = offsetof(struct dentry, d_name) + name_len + 1; + if (to_write > available) { + break; + } + + dent.d_reclen = to_write; + kern_iovec_t iov[] = { + IOVEC(&dent, offsetof(struct dentry, d_name)), + IOVEC(child->e_dentry.d_name, name_len + 1), + }; + size_t tmp = 0; + kern_status_t status + = xpc_buffer_writev(out, bytes_written, iov, 2, &tmp); + if (status != KERN_OK) { + break; + } + + bytes_written += tmp; + available -= tmp; + offset++; + } + + *seek = offset; + out->buf_len = bytes_written; + + return FS_SUCCESS; +} + static const struct fs_file_ops file_ops = { .f_read = file_read, }; +static const struct fs_file_ops dir_ops = { + .f_readdir = dir_readdir, +}; + static const struct fs_inode_ops file_inode_ops = { .i_lookup = NULL, }; @@ -224,6 +299,7 @@ static struct tar_entry *create_dir_entry( entry->e_inode.i_sb = &sb->sb_base; entry->e_inode.i_mode = FS_INODE_DIR; entry->e_inode.i_ops = &dir_inode_ops; + entry->e_inode.i_fops = &dir_ops; entry->e_dentry.d_sb = &sb->sb_base; entry->e_dentry.d_ops = &dentry_ops;