#include "file_system_struct.h"
#include "bin.h"
#include "ro_fs.h"
#include "pfs.h"
#include "pfs_structs.h"
#include <time.h>
#include <stat_struct.h>
#include <verify_area.h>
#include <areas.h>
#include <usr_hdr.h>
#include <segment.h>
#include <consts.h>
#include <enums.h>
#include <errno.h>
#include <string.h>
#include <stddef.h>
struct rootfs_file_struct;
struct rootfs_file_operations_struct {
int (*find)(const struct rootfs_file_struct *, const char *, unsigned long *, int *);
int (*get_name)(const struct rootfs_file_struct *, char []);
int (*get_size)(const struct rootfs_file_struct *, unsigned long *);
int (*read_dir)(const struct rootfs_file_struct *, unsigned long, char *, unsigned int);
int (*read)(const struct rootfs_file_struct *, unsigned long, char *, unsigned int);
};
struct rootfs_file_struct {
struct pfs_dir_entry_struct dir_entry;
union {
struct pfs_dir_struct dir;
const void *bin_addr;
};
const struct rootfs_file_operations_struct *operations;
};
static int mount_count;
static long mount_time;
static int stat(const struct rootfs_file_struct *file, struct stat_struct *fs_buf)
{
struct stat_struct statbuf;
int rv;
if (!verify_area(fs_buf, sizeof (struct stat_struct), PF_WRITE))
return -EFAULT;
statbuf.dev = DEV_NONE;
statbuf.id = file->dir_entry.info.id;
statbuf.type = file->dir_entry.info.type;
statbuf.rdev = DEV_NONE;
if (file->dir_entry.info.type == FT_REG) {
if ((rv = file->operations->get_size(file, &statbuf.size)) < 0)
return rv;
}
else
statbuf.size = 0;
statbuf.mtime = mount_time;
memcpy_tofs(fs_buf, &statbuf, sizeof (struct stat_struct));
return 0;
}
static int root_find(const struct rootfs_file_struct *file, const char *fs_basename, unsigned long *id, int *type)
{
return pfs_find(&file->dir, fs_basename, id, type);
}
static int root_get_name(const struct rootfs_file_struct *file, char name[])
{
strcpy(name, file->dir_entry.info.name);
return 0;
}
static int root_read_dir(const struct rootfs_file_struct *file, unsigned long pos, char *fs_buf, unsigned int count)
{
return pfs_read_dir(&file->dir, pos, fs_buf, count);
}
static int rootfs_bin_find(const struct rootfs_file_struct *file, const char *fs_basename, unsigned long *id, int *type)
{
return bin_find(file->bin_addr, fs_basename, id, type);
}
static int rootfs_bin_get_name(const struct rootfs_file_struct *file, char name[])
{
return bin_get_name(file->bin_addr, name);
}
static int rootfs_bin_read_dir(const struct rootfs_file_struct *file, unsigned long pos, char *fs_buf, unsigned int count)
{
return bin_read_dir(file->bin_addr, pos, fs_buf, count);
}
static int rootfs_bin_get_size(const struct rootfs_file_struct *file, unsigned long *size)
{
return bin_get_size(file->bin_addr, size);
}
static int rootfs_bin_read(const struct rootfs_file_struct *file, unsigned long pos, char *fs_buf, unsigned int count)
{
return bin_read(file->bin_addr, pos, fs_buf, count);
}
static const struct rootfs_file_operations_struct root_dir_operations = {
.find = root_find,
.get_name = root_get_name,
.read_dir = root_read_dir
};
static const struct rootfs_file_operations_struct bin_dir_operations = {
.find = rootfs_bin_find,
.get_name = root_get_name,
.read_dir = rootfs_bin_read_dir
};
static const struct rootfs_file_operations_struct bin_file_operations = {
.get_size = rootfs_bin_get_size,
.get_name = rootfs_bin_get_name,
.read = rootfs_bin_read
};
static struct rootfs_file_struct root_dir = {
.dir_entry = {
.info = {
.type = FT_DIR
}
},
.operations = &root_dir_operations
};
static struct rootfs_file_struct dev_dir = {
.dir_entry = {
.info = {
.name = "dev",
.type = FT_DIR
}
},
.operations = &root_dir_operations
};
static struct rootfs_file_struct proc_dir = {
.dir_entry = {
.info = {
.name = "proc",
.type = FT_DIR
}
},
.operations = &root_dir_operations
};
static struct rootfs_file_struct bin_dir = {
.dir_entry = {
.info = {
.name = "bin",
.type = FT_DIR
}
},
.operations = &bin_dir_operations
};
static struct rootfs_file_struct lib_dir = {
.dir_entry = {
.info = {
.name = "lib",
.type = FT_DIR
}
},
.operations = &bin_dir_operations
};
static struct rootfs_file_struct floppy_dir = {
.dir_entry = {
.info = {
.name = "floppy",
.type = FT_DIR
}
},
.operations = &root_dir_operations
};
static struct rootfs_file_struct home_dir = {
.dir_entry = {
.info = {
.name = "home",
.type = FT_DIR
}
},
.operations = &root_dir_operations
};
static struct rootfs_file_struct *const root_file_index[] = {
&root_dir,
&dev_dir,
&proc_dir,
&bin_dir,
&lib_dir,
&floppy_dir,
&home_dir
};
static const unsigned int root_file_index_size = sizeof root_file_index / sizeof root_file_index[0];
static void build_bin_file(struct rootfs_file_struct *file, const void *bin_addr)
{
file->dir_entry.info.id = (unsigned long)bin_addr;
file->dir_entry.info.type = FT_REG;
file->bin_addr = bin_addr;
file->operations = &bin_file_operations;
}
static int init()
{
unsigned int i;
for (i = 0; i < root_file_index_size; i++)
root_file_index[i]->dir_entry.info.id = i;
pfs_init_dir(&root_dir.dir);
pfs_init_dir(&dev_dir.dir);
pfs_init_dir(&proc_dir.dir);
bin_dir.bin_addr = usr_start + ((const usr_hdr_t *)usr_start)->bin_offset;
if (!bin_check(bin_dir.bin_addr))
return -EINVAL;
lib_dir.bin_addr = usr_start + ((const usr_hdr_t *)usr_start)->lib_offset;
if (!bin_check(lib_dir.bin_addr))
return -EINVAL;
pfs_init_dir(&floppy_dir.dir);
pfs_init_dir(&home_dir.dir);
for (i = 1; i < root_file_index_size; i++)
pfs_insert_dir_entry(&root_file_index[i]->dir_entry, &root_dir.dir);
return 0;
}
static struct rootfs_file_struct *get_file(unsigned long id, struct rootfs_file_struct *filebuf)
{
if (id < root_file_index_size)
return root_file_index[id];
else {
build_bin_file(filebuf, (void *)id);
return filebuf;
}
}
static int rootfs_mount(const struct device_struct *device, void **data)
{
int rv;
if (!mount_count) {
mount_time = get_time();
if ((rv = init()) < 0)
return rv;
}
mount_count++;
*data = NULL;
return 0;
}
static void rootfs_umount(void *data)
{
mount_count--;
}
static int rootfs_find(void *data, unsigned long dir_id, const char *fs_basename, unsigned long *id, int *type)
{
struct rootfs_file_struct filebuf;
const struct rootfs_file_struct *file;
file = get_file(dir_id, &filebuf);
return file->operations->find(file, fs_basename, id, type);
}
static int rootfs_get_name(void *data, unsigned long id, char name[])
{
struct rootfs_file_struct filebuf;
const struct rootfs_file_struct *file;
file = get_file(id, &filebuf);
return file->operations->get_name(file, name);
}
static int rootfs_get_size(void *data, unsigned long reg_id, unsigned long *size)
{
struct rootfs_file_struct filebuf;
const struct rootfs_file_struct *file;
file = get_file(reg_id, &filebuf);
return file->operations->get_size(file, size);
}
static int rootfs_stat(void *data, unsigned long id, struct stat_struct *fs_buf)
{
struct rootfs_file_struct filebuf;
return stat(get_file(id, &filebuf), fs_buf);
}
static int rootfs_read_dir(void *data, unsigned long dir_id, unsigned long pos, char *fs_buf, unsigned int count)
{
struct rootfs_file_struct filebuf;
const struct rootfs_file_struct *file;
file = get_file(dir_id, &filebuf);
return file->operations->read_dir(file, pos, fs_buf, count);
}
static int rootfs_read(void *data, unsigned long leaf_id, unsigned long pos, char *fs_buf, unsigned int count)
{
struct rootfs_file_struct filebuf;
const struct rootfs_file_struct *file;
file = get_file(leaf_id, &filebuf);
return file->operations->read(file, pos, fs_buf, count);
}
const struct file_system_struct rootfs = {
.name = "rootfs",
.type = FT_NONE,
.mount = rootfs_mount,
.umount = rootfs_umount,
.find = rootfs_find,
.get_name = rootfs_get_name,
.get_device = NULL,
.get_size = rootfs_get_size,
.stat = rootfs_stat,
.read_dir = rootfs_read_dir,
.read = rootfs_read,
.write = no_write,
.ioctl = NULL,
.create = no_create,
.mkdir = no_mkdir,
.can_remove = no_can_remove,
.remove = no_remove,
.rmdir = no_rmdir,
.rename = no_rename
};