bootstrap: tar: implement readdir()
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include <mango/vm.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <xpc/buffer.h>
|
||||
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user