bootstrap: tar: implement readdir()
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
#include <mango/vm.h>
|
#include <mango/vm.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <xpc/buffer.h>
|
#include <xpc/buffer.h>
|
||||||
|
|
||||||
struct tar_superblock {
|
struct tar_superblock {
|
||||||
@@ -148,6 +149,24 @@ static struct tar_entry *entry_get_child(
|
|||||||
return NULL;
|
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 const struct fs_dentry_ops dentry_ops = {};
|
||||||
|
|
||||||
static enum fs_status dir_lookup(
|
static enum fs_status dir_lookup(
|
||||||
@@ -189,7 +208,7 @@ static enum fs_status file_read(
|
|||||||
|
|
||||||
char *src = (char *)entry->e_data + offset;
|
char *src = (char *)entry->e_data + offset;
|
||||||
size_t w;
|
size_t w;
|
||||||
xpc_buffer_write(buf, src, count, &w);
|
xpc_buffer_write(buf, 0, src, count, &w);
|
||||||
|
|
||||||
offset += w;
|
offset += w;
|
||||||
*seek = offset;
|
*seek = offset;
|
||||||
@@ -197,10 +216,66 @@ static enum fs_status file_read(
|
|||||||
return FS_SUCCESS;
|
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 = {
|
static const struct fs_file_ops file_ops = {
|
||||||
.f_read = file_read,
|
.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 = {
|
static const struct fs_inode_ops file_inode_ops = {
|
||||||
.i_lookup = NULL,
|
.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_sb = &sb->sb_base;
|
||||||
entry->e_inode.i_mode = FS_INODE_DIR;
|
entry->e_inode.i_mode = FS_INODE_DIR;
|
||||||
entry->e_inode.i_ops = &dir_inode_ops;
|
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_sb = &sb->sb_base;
|
||||||
entry->e_dentry.d_ops = &dentry_ops;
|
entry->e_dentry.d_ops = &dentry_ops;
|
||||||
|
|||||||
Reference in New Issue
Block a user