bootstrap: update tarfs driver with libfs support
This commit is contained in:
@@ -6,7 +6,7 @@ set_property(SOURCE ${arch_sources} PROPERTY LANGUAGE C)
|
|||||||
add_executable(bootstrap ${c_sources} ${arch_sources})
|
add_executable(bootstrap ${c_sources} ${arch_sources})
|
||||||
|
|
||||||
target_link_libraries(bootstrap
|
target_link_libraries(bootstrap
|
||||||
libmango libc-core libc-malloc libfs-static liblaunch
|
libmango libc-core libc-malloc libfs-static liblaunch libxpc-static
|
||||||
interface::fs)
|
interface::fs)
|
||||||
|
|
||||||
target_compile_options(bootstrap PRIVATE
|
target_compile_options(bootstrap PRIVATE
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ static enum launch_status resolve_dependency(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static kern_status_t open(
|
static kern_status_t open(
|
||||||
const struct msg_endpoint *sender,
|
xpc_context_t *ctx,
|
||||||
|
const xpc_endpoint_t *sender,
|
||||||
const char *path,
|
const char *path,
|
||||||
int flags,
|
int flags,
|
||||||
int *out_err,
|
int *out_err,
|
||||||
@@ -178,51 +179,46 @@ int main(
|
|||||||
.fs_arg = &heap,
|
.fs_arg = &heap,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fs_context *fs = fs_context_create(&fs_allocator, NULL);
|
struct fs_context *fs = fs_context_create(&fs_allocator);
|
||||||
if (!fs) {
|
if (!fs) {
|
||||||
kern_logf("cannot initialise fs");
|
kern_logf("cannot initialise fs");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum fs_status fs_status = fs_context_mount_filesystem(
|
||||||
|
fs,
|
||||||
|
tar_mount,
|
||||||
|
(void *)bsp_base,
|
||||||
|
0);
|
||||||
|
if (fs_status != FS_SUCCESS) {
|
||||||
|
kern_logf("cannot mount filesustem (%d)", fs_status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct msg_endpoint sender;
|
xpc_msg_t msg;
|
||||||
struct msg_header hdr;
|
kern_status_t status = xpc_msg_recv(channel, &msg);
|
||||||
kern_msg_handle_t handles[KERN_MSG_MAX_HANDLES] = {0};
|
|
||||||
kern_status_t status = msg_recv_generic(
|
|
||||||
channel,
|
|
||||||
&sender,
|
|
||||||
&hdr,
|
|
||||||
handles,
|
|
||||||
KERN_MSG_MAX_HANDLES);
|
|
||||||
if (status != KERN_OK) {
|
if (status != KERN_OK) {
|
||||||
kern_logf("message recv error %d", status);
|
kern_logf("message recv error %d", status);
|
||||||
msg_reply_generic(
|
|
||||||
channel,
|
|
||||||
&sender,
|
|
||||||
&hdr,
|
|
||||||
KERN_UNSUPPORTED);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (hdr.hdr_protocol) {
|
switch (msg.msg_header.hdr_interface) {
|
||||||
case PROTOCOL_FS:
|
case INTERFACE_FS:
|
||||||
status = fs_context_dispatch_msg(
|
status = fs_context_dispatch_msg(fs, &msg);
|
||||||
fs,
|
|
||||||
channel,
|
|
||||||
&sender,
|
|
||||||
&hdr);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
kern_logf(
|
kern_logf(
|
||||||
"unknown message protocol %u",
|
"unknown message protocol %u",
|
||||||
hdr.hdr_protocol);
|
msg.msg_header.hdr_interface);
|
||||||
msg_reply_generic(
|
xpc_msg_reply_error(&msg, KERN_UNSUPPORTED);
|
||||||
channel,
|
|
||||||
&sender,
|
|
||||||
&hdr,
|
|
||||||
KERN_UNSUPPORTED);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
kern_logf("message reply error %d", status);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
138
sys/bootstrap/queue.c
Normal file
138
sys/bootstrap/queue.c
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
size_t queue_length(struct queue *q)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
struct queue_entry *x = q->q_first;
|
||||||
|
while (x) {
|
||||||
|
i++;
|
||||||
|
x = x->qe_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_insert_before(
|
||||||
|
struct queue *q,
|
||||||
|
struct queue_entry *entry,
|
||||||
|
struct queue_entry *before)
|
||||||
|
{
|
||||||
|
struct queue_entry *x = before->qe_prev;
|
||||||
|
if (x) {
|
||||||
|
x->qe_next = entry;
|
||||||
|
} else {
|
||||||
|
q->q_first = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->qe_prev = x;
|
||||||
|
|
||||||
|
before->qe_prev = entry;
|
||||||
|
entry->qe_next = before;
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_insert_after(
|
||||||
|
struct queue *q,
|
||||||
|
struct queue_entry *entry,
|
||||||
|
struct queue_entry *after)
|
||||||
|
{
|
||||||
|
struct queue_entry *x = after->qe_next;
|
||||||
|
if (x) {
|
||||||
|
x->qe_prev = entry;
|
||||||
|
} else {
|
||||||
|
q->q_last = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->qe_prev = x;
|
||||||
|
|
||||||
|
after->qe_next = entry;
|
||||||
|
entry->qe_prev = after;
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_push_front(struct queue *q, struct queue_entry *entry)
|
||||||
|
{
|
||||||
|
if (q->q_first) {
|
||||||
|
q->q_first->qe_prev = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->qe_next = q->q_first;
|
||||||
|
entry->qe_prev = NULL;
|
||||||
|
|
||||||
|
q->q_first = entry;
|
||||||
|
|
||||||
|
if (!q->q_last) {
|
||||||
|
q->q_last = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_push_back(struct queue *q, struct queue_entry *entry)
|
||||||
|
{
|
||||||
|
if (q->q_last) {
|
||||||
|
q->q_last->qe_next = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->qe_prev = q->q_last;
|
||||||
|
entry->qe_next = NULL;
|
||||||
|
|
||||||
|
q->q_last = entry;
|
||||||
|
|
||||||
|
if (!q->q_first) {
|
||||||
|
q->q_first = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct queue_entry *queue_pop_front(struct queue *q)
|
||||||
|
{
|
||||||
|
struct queue_entry *x = q->q_first;
|
||||||
|
if (x) {
|
||||||
|
queue_delete(q, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct queue_entry *queue_pop_back(struct queue *q)
|
||||||
|
{
|
||||||
|
struct queue_entry *x = q->q_last;
|
||||||
|
if (x) {
|
||||||
|
queue_delete(q, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_delete(struct queue *q, struct queue_entry *entry)
|
||||||
|
{
|
||||||
|
if (!entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == q->q_first) {
|
||||||
|
q->q_first = q->q_first->qe_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == q->q_last) {
|
||||||
|
q->q_last = q->q_last->qe_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->qe_next) {
|
||||||
|
entry->qe_next->qe_prev = entry->qe_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->qe_prev) {
|
||||||
|
entry->qe_prev->qe_next = entry->qe_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->qe_next = entry->qe_prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_delete_all(struct queue *q)
|
||||||
|
{
|
||||||
|
struct queue_entry *x = q->q_first;
|
||||||
|
while (x) {
|
||||||
|
struct queue_entry *next = x->qe_next;
|
||||||
|
x->qe_next = x->qe_prev = NULL;
|
||||||
|
x = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
q->q_first = q->q_last = NULL;
|
||||||
|
}
|
||||||
100
sys/bootstrap/queue.h
Normal file
100
sys/bootstrap/queue.h
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#ifndef QUEUE_H_
|
||||||
|
#define QUEUE_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define QUEUE_CONTAINER(t, m, v) \
|
||||||
|
((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
|
||||||
|
|
||||||
|
#define QUEUE_INIT ((struct queue) {.q_first = NULL, .q_last = NULL})
|
||||||
|
#define QUEUE_ENTRY_INIT \
|
||||||
|
((struct queue_entry) {.qe_next = NULL, .qe_prev = NULL})
|
||||||
|
|
||||||
|
#define queue_foreach(iter_type, iter_name, queue_name, node_member) \
|
||||||
|
for (iter_type *iter_name = (iter_type *)QUEUE_CONTAINER( \
|
||||||
|
iter_type, \
|
||||||
|
node_member, \
|
||||||
|
queue_first(queue_name)); \
|
||||||
|
iter_name; \
|
||||||
|
iter_name = (iter_type *)QUEUE_CONTAINER( \
|
||||||
|
iter_type, \
|
||||||
|
node_member, \
|
||||||
|
queue_next(&((iter_name)->node_member))))
|
||||||
|
|
||||||
|
#define queue_foreach_r(iter_type, iter_name, queue_name, node_member) \
|
||||||
|
for (iter_type *iter_name = (iter_type *)QUEUE_CONTAINER( \
|
||||||
|
iter_type, \
|
||||||
|
node_member, \
|
||||||
|
queue_last(queue_name)); \
|
||||||
|
iter_name; \
|
||||||
|
iter_name = (iter_type *)QUEUE_CONTAINER( \
|
||||||
|
iter_type, \
|
||||||
|
node_member, \
|
||||||
|
queue_prev(&((iter_name)->node_member))))
|
||||||
|
|
||||||
|
struct queue_entry {
|
||||||
|
struct queue_entry *qe_next;
|
||||||
|
struct queue_entry *qe_prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct queue {
|
||||||
|
struct queue_entry *q_first;
|
||||||
|
struct queue_entry *q_last;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void queue_init(struct queue *q)
|
||||||
|
{
|
||||||
|
memset(q, 0x00, sizeof *q);
|
||||||
|
}
|
||||||
|
static inline bool queue_empty(struct queue *q)
|
||||||
|
{
|
||||||
|
return q->q_first == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct queue_entry *queue_first(struct queue *q)
|
||||||
|
{
|
||||||
|
return q->q_first;
|
||||||
|
}
|
||||||
|
static inline struct queue_entry *queue_last(struct queue *q)
|
||||||
|
{
|
||||||
|
return q->q_last;
|
||||||
|
}
|
||||||
|
static inline struct queue_entry *queue_next(struct queue_entry *entry)
|
||||||
|
{
|
||||||
|
return entry->qe_next;
|
||||||
|
}
|
||||||
|
static inline struct queue_entry *queue_prev(struct queue_entry *entry)
|
||||||
|
{
|
||||||
|
return entry->qe_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern size_t queue_length(struct queue *q);
|
||||||
|
|
||||||
|
extern void queue_insert_before(
|
||||||
|
struct queue *q,
|
||||||
|
struct queue_entry *entry,
|
||||||
|
struct queue_entry *before);
|
||||||
|
extern void queue_insert_after(
|
||||||
|
struct queue *q,
|
||||||
|
struct queue_entry *entry,
|
||||||
|
struct queue_entry *after);
|
||||||
|
|
||||||
|
extern void queue_push_front(struct queue *q, struct queue_entry *entry);
|
||||||
|
extern void queue_push_back(struct queue *q, struct queue_entry *entry);
|
||||||
|
|
||||||
|
extern struct queue_entry *queue_pop_front(struct queue *q);
|
||||||
|
extern struct queue_entry *queue_pop_back(struct queue *q);
|
||||||
|
|
||||||
|
extern void queue_delete(struct queue *q, struct queue_entry *entry);
|
||||||
|
extern void queue_delete_all(struct queue *q);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,8 +1,30 @@
|
|||||||
#include "tar.h"
|
#include "tar.h"
|
||||||
|
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
#include <fs/dentry.h>
|
||||||
|
#include <fs/file.h>
|
||||||
|
#include <fs/inode.h>
|
||||||
|
#include <fs/superblock.h>
|
||||||
#include <mango/handle.h>
|
#include <mango/handle.h>
|
||||||
|
#include <mango/log.h>
|
||||||
#include <mango/vm.h>
|
#include <mango/vm.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <xpc/buffer.h>
|
||||||
|
|
||||||
|
struct tar_superblock {
|
||||||
|
struct fs_superblock sb_base;
|
||||||
|
struct tar_bin_header *sb_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tar_entry {
|
||||||
|
struct fs_dentry e_dentry;
|
||||||
|
struct fs_inode e_inode;
|
||||||
|
void *e_data;
|
||||||
|
struct queue_entry e_entry;
|
||||||
|
struct queue e_children;
|
||||||
|
};
|
||||||
|
|
||||||
size_t getsize(const char *in)
|
size_t getsize(const char *in)
|
||||||
{
|
{
|
||||||
@@ -94,3 +116,300 @@ int tar_header_decode(const struct tar_bin_header *in, struct tar_header *out)
|
|||||||
out->size = getsize(in->size);
|
out->size = getsize(in->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct tar_entry *entry_from_dentry(struct fs_dentry *dent)
|
||||||
|
{
|
||||||
|
return QUEUE_CONTAINER(struct tar_entry, e_dentry, dent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tar_entry *entry_from_inode(struct fs_inode *inode)
|
||||||
|
{
|
||||||
|
return QUEUE_CONTAINER(struct tar_entry, e_inode, inode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tar_entry *entry_get_child(
|
||||||
|
struct tar_entry *entry,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct queue_entry *cur = queue_first(&entry->e_children);
|
||||||
|
while (cur) {
|
||||||
|
struct tar_entry *child
|
||||||
|
= QUEUE_CONTAINER(struct tar_entry, e_entry, cur);
|
||||||
|
|
||||||
|
if (!strcmp(child->e_dentry.d_name, name)) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = queue_next(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fs_dentry_ops dentry_ops = {};
|
||||||
|
|
||||||
|
static enum fs_status dir_lookup(
|
||||||
|
struct fs_inode *inode,
|
||||||
|
const char *name,
|
||||||
|
struct fs_dentry **out)
|
||||||
|
{
|
||||||
|
struct tar_entry *entry = entry_from_inode(inode);
|
||||||
|
struct tar_entry *child = entry_get_child(entry, name);
|
||||||
|
if (!child) {
|
||||||
|
return FS_ERR_NO_ENTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = &child->e_dentry;
|
||||||
|
return FS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum fs_status file_read(
|
||||||
|
struct fs_file *f,
|
||||||
|
xpc_buffer_t *buf,
|
||||||
|
size_t count,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset >= entry->e_inode.i_size) {
|
||||||
|
count = 0;
|
||||||
|
} else if (offset + count > entry->e_inode.i_size) {
|
||||||
|
count = entry->e_inode.i_size - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
return FS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *src = (char *)entry->e_data + offset;
|
||||||
|
size_t w;
|
||||||
|
xpc_buffer_write(buf, src, count, &w);
|
||||||
|
|
||||||
|
offset += count;
|
||||||
|
*seek = offset;
|
||||||
|
|
||||||
|
return FS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fs_file_ops file_ops = {
|
||||||
|
.f_read = file_read,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fs_inode_ops file_inode_ops = {
|
||||||
|
.i_lookup = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fs_inode_ops dir_inode_ops = {
|
||||||
|
.i_lookup = dir_lookup,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct tar_entry *create_dir_entry(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
struct tar_superblock *sb,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct tar_entry *entry = fs_context_alloc(ctx, sizeof *entry);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(entry, 0x0, sizeof *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_dentry.d_sb = &sb->sb_base;
|
||||||
|
entry->e_dentry.d_ops = &dentry_ops;
|
||||||
|
entry->e_dentry.d_inode = &entry->e_inode;
|
||||||
|
|
||||||
|
size_t name_len = strlen(name);
|
||||||
|
entry->e_dentry.d_name = fs_context_alloc(ctx, name_len + 1);
|
||||||
|
if (!entry->e_dentry.d_name) {
|
||||||
|
fs_context_free(ctx, entry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(entry->e_dentry.d_name, name, name_len + 1);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tar_entry *create_file_entry(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
struct tar_superblock *sb,
|
||||||
|
struct tar_header *header,
|
||||||
|
void *data,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct tar_entry *entry = fs_context_alloc(ctx, sizeof *entry);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(entry, 0x0, sizeof *entry);
|
||||||
|
|
||||||
|
entry->e_inode.i_sb = &sb->sb_base;
|
||||||
|
entry->e_inode.i_mode = FS_INODE_REG;
|
||||||
|
entry->e_inode.i_ops = &file_inode_ops;
|
||||||
|
entry->e_inode.i_fops = &file_ops;
|
||||||
|
entry->e_inode.i_size = header->size;
|
||||||
|
|
||||||
|
entry->e_dentry.d_sb = &sb->sb_base;
|
||||||
|
entry->e_dentry.d_ops = &dentry_ops;
|
||||||
|
entry->e_dentry.d_inode = &entry->e_inode;
|
||||||
|
|
||||||
|
entry->e_data = data;
|
||||||
|
|
||||||
|
size_t name_len = strlen(name);
|
||||||
|
entry->e_dentry.d_name = fs_context_alloc(ctx, name_len + 1);
|
||||||
|
if (!entry->e_dentry.d_name) {
|
||||||
|
fs_context_free(ctx, entry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(entry->e_dentry.d_name, name, name_len + 1);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t get_first_path_component(const char *in, char *out, size_t max)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < max - 1) {
|
||||||
|
if (in[i] == '\0' || in[i] == '/') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out[i] = in[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out[i] = '\0';
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum fs_status add_entry_to_tree(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
struct tar_superblock *sb,
|
||||||
|
struct tar_header *entry,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct tar_entry *cur = entry_from_dentry(sb->sb_base.s_root);
|
||||||
|
const char *path = entry->filename;
|
||||||
|
|
||||||
|
char tok[256];
|
||||||
|
|
||||||
|
while (*path != '\0') {
|
||||||
|
while (*path == '/') {
|
||||||
|
path++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t tok_len
|
||||||
|
= get_first_path_component(path, tok, sizeof tok);
|
||||||
|
|
||||||
|
if (!tok_len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tar_entry *next = entry_get_child(cur, tok);
|
||||||
|
bool is_file = *(path + tok_len) == '\0';
|
||||||
|
if (next) {
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_file) {
|
||||||
|
next = create_file_entry(ctx, sb, entry, data, tok);
|
||||||
|
} else {
|
||||||
|
next = create_dir_entry(ctx, sb, tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!next) {
|
||||||
|
return FS_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_push_back(&cur->e_children, &next->e_entry);
|
||||||
|
next->e_dentry.d_parent = &cur->e_dentry;
|
||||||
|
|
||||||
|
next:
|
||||||
|
cur = next;
|
||||||
|
path += tok_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum fs_status build_dentry_tree(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
struct tar_superblock *sb)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct tar_entry *root = create_dir_entry(ctx, sb, "/");
|
||||||
|
if (!root) {
|
||||||
|
return FS_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb->sb_base.s_root = &root->e_dentry;
|
||||||
|
struct tar_bin_header *bin_header = sb->sb_data;
|
||||||
|
struct tar_header header;
|
||||||
|
enum fs_status status = FS_SUCCESS;
|
||||||
|
|
||||||
|
for (size_t i = 0;; i++) {
|
||||||
|
tar_header_decode(bin_header, &header);
|
||||||
|
if (bin_header->filename[0] == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *s = (char *)bin_header;
|
||||||
|
s += sizeof *bin_header;
|
||||||
|
|
||||||
|
bool add = true;
|
||||||
|
|
||||||
|
if (!strcmp(header.filename, "././@PaxHeader")) {
|
||||||
|
add = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (add) {
|
||||||
|
status = add_entry_to_tree(ctx, sb, &header, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != FS_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
s += header.size;
|
||||||
|
s += ((sizeof *bin_header)
|
||||||
|
- ((uintptr_t)s % (sizeof *bin_header)));
|
||||||
|
|
||||||
|
bin_header = (struct tar_bin_header *)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum fs_status tar_mount(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
void *arg,
|
||||||
|
enum fs_mount_flags flags,
|
||||||
|
struct fs_superblock **out)
|
||||||
|
{
|
||||||
|
struct tar_superblock *sb = fs_context_alloc(ctx, sizeof *sb);
|
||||||
|
if (!sb) {
|
||||||
|
return FS_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb->sb_data = arg;
|
||||||
|
|
||||||
|
enum fs_status status = build_dentry_tree(ctx, sb);
|
||||||
|
if (status != FS_SUCCESS) {
|
||||||
|
fs_context_free(ctx, sb);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = (struct fs_superblock *)sb;
|
||||||
|
return FS_SUCCESS;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef TAR_H_
|
#ifndef TAR_H_
|
||||||
#define TAR_H_
|
#define TAR_H_
|
||||||
|
|
||||||
|
#include <fs/context.h>
|
||||||
|
#include <fs/status.h>
|
||||||
#include <mango/types.h>
|
#include <mango/types.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -42,4 +44,10 @@ extern int tar_header_decode(
|
|||||||
const struct tar_bin_header *in,
|
const struct tar_bin_header *in,
|
||||||
struct tar_header *out);
|
struct tar_header *out);
|
||||||
|
|
||||||
|
extern enum fs_status tar_mount(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
void *arg,
|
||||||
|
enum fs_mount_flags flags,
|
||||||
|
struct fs_superblock **out);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user