mufs: add support for directories
This commit is contained in:
parent
99e2229bbb
commit
e18107d2d5
6 changed files with 272 additions and 9 deletions
1
Makefile
1
Makefile
|
@ -24,6 +24,7 @@ obj-y += source/main.o
|
||||||
obj-y += source/core/flash.o
|
obj-y += source/core/flash.o
|
||||||
|
|
||||||
obj-y += source/fs/mufs/block.o
|
obj-y += source/fs/mufs/block.o
|
||||||
|
obj-y += source/fs/mufs/dir.o
|
||||||
obj-y += source/fs/mufs/super.o
|
obj-y += source/fs/mufs/super.o
|
||||||
obj-y += source/fs/mufs/tree.o
|
obj-y += source/fs/mufs/tree.o
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ struct mufs_dir;
|
||||||
|
|
||||||
struct mufs_tree {
|
struct mufs_tree {
|
||||||
struct mufs *fs;
|
struct mufs *fs;
|
||||||
|
uint32_t va;
|
||||||
uint32_t file_size;
|
uint32_t file_size;
|
||||||
uint32_t root;
|
uint32_t root;
|
||||||
uint8_t depth;
|
uint8_t depth;
|
||||||
|
|
210
source/fs/mufs/dir.c
Normal file
210
source/fs/mufs/dir.c
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <flash.h>
|
||||||
|
#include <macros.h>
|
||||||
|
|
||||||
|
#include <fs/mufs.h>
|
||||||
|
|
||||||
|
#include "dir.h"
|
||||||
|
#include "tree.h"
|
||||||
|
|
||||||
|
struct mufs_dir {
|
||||||
|
struct mufs *fs;
|
||||||
|
struct mufs_tree *tree;
|
||||||
|
uint32_t va;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int resolve(struct mufs *fs, struct mufs_tree *tree, const char *path)
|
||||||
|
{
|
||||||
|
if (!path || *path == '\0') {
|
||||||
|
memcpy(tree, &fs->root, sizeof *tree);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: resolve directories. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mufs_dir *mufs_opendir(struct mufs *fs, const char *path)
|
||||||
|
{
|
||||||
|
struct mufs_dir *dir;
|
||||||
|
|
||||||
|
if (!(dir = malloc(sizeof *dir)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dir->fs = fs;
|
||||||
|
|
||||||
|
/* TODO: resolve path */
|
||||||
|
(void)path;
|
||||||
|
memcpy(&dir->tree, &fs->root, sizeof dir->tree);
|
||||||
|
dir->va = 0;
|
||||||
|
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mufs_closedir(struct mufs_dir *dir)
|
||||||
|
{
|
||||||
|
if (!dir)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t read_dirent(struct mufs *fs, struct mufs_tree *tree,
|
||||||
|
struct mufs_dirent *dirent, uint32_t va)
|
||||||
|
{
|
||||||
|
struct mufs_dentry entry;
|
||||||
|
size_t ret = 0;
|
||||||
|
size_t len;
|
||||||
|
uint32_t base = va;
|
||||||
|
|
||||||
|
if (va + sizeof(entry) > tree->file_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (mufs_read(tree, &entry, va, sizeof entry) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!entry.type)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret += sizeof entry;
|
||||||
|
va += sizeof entry;
|
||||||
|
len = min(entry.path_len, sizeof(dirent->path - 1));
|
||||||
|
|
||||||
|
if (va + len > tree->file_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (mufs_read(tree, dirent->path, va, len) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dirent->path[len] = '\0';
|
||||||
|
ret += len;
|
||||||
|
|
||||||
|
dirent->type = entry.type;
|
||||||
|
|
||||||
|
struct flash_dev *dev = fs->dev;
|
||||||
|
|
||||||
|
if (mufs_lookup_page(tree, &dirent->tree.va, base & ~((UINT32_C(1) << dev->log2_block_size) - 1)) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dirent->tree.fs = fs;
|
||||||
|
dirent->tree.va |= base & ((UINT32_C(1) << dev->log2_block_size) - 1);
|
||||||
|
dirent->tree.file_size = entry.file_size;
|
||||||
|
dirent->tree.root = entry.root;
|
||||||
|
dirent->tree.depth = entry.depth;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mufs_dtree {
|
||||||
|
uint32_t file_size;
|
||||||
|
uint32_t root;
|
||||||
|
uint8_t depth;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
static size_t write_dirent(struct mufs_tree *tree,
|
||||||
|
uint32_t va, struct mufs_dirent *dirent)
|
||||||
|
{
|
||||||
|
struct mufs_dtree dtree;
|
||||||
|
struct mufs_dentry entry;
|
||||||
|
|
||||||
|
entry.type = dirent->type;
|
||||||
|
entry.file_size = dirent->tree.file_size;
|
||||||
|
entry.root = dirent->tree.root;
|
||||||
|
entry.depth = dirent->tree.depth;
|
||||||
|
entry.path_len = strlen(dirent->path);
|
||||||
|
|
||||||
|
if (mufs_write(tree, dirent->path, va + sizeof entry,
|
||||||
|
entry.path_len) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (mufs_write(tree, &entry, va, sizeof entry) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tree->file_size = max(tree->file_size, va + sizeof entry + entry.path_len);
|
||||||
|
|
||||||
|
dtree.file_size = tree->file_size;
|
||||||
|
dtree.root = tree->root;
|
||||||
|
dtree.depth = tree->depth;
|
||||||
|
|
||||||
|
printf("tree->va=%u\n", tree->va);
|
||||||
|
|
||||||
|
if (flash_write(tree->fs->dev, tree->va, &dtree, sizeof dtree) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return entry.path_len + sizeof entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mufs_readdir(struct mufs_dir *dir, struct mufs_dirent *dirent)
|
||||||
|
{
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
|
if (!dir || !dirent || dir->va >= dir->tree->file_size)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((ret = read_dirent(dir->fs, dir->tree, dirent, dir->va)) > 0) {
|
||||||
|
dir->va += ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir->va = align_up(dir->va + 1, dir->fs->dev->log2_block_size);
|
||||||
|
|
||||||
|
if ((ret = read_dirent(dir->fs, dir->tree, dirent, dir->va)) > 0) {
|
||||||
|
dir->va += ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("return?\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mufs_mkdir(struct mufs *fs, const char *path)
|
||||||
|
{
|
||||||
|
struct mufs_dirent dirent;
|
||||||
|
struct mufs_tree tree;
|
||||||
|
size_t len;
|
||||||
|
char *s;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!(s = strdup(path)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!(name = strrchr(s, '/'))) {
|
||||||
|
name = s;
|
||||||
|
s = NULL;
|
||||||
|
} else {
|
||||||
|
*name++ = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*name == '\0')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (resolve(fs, &tree, s) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = min(strlen(name), sizeof(dirent.path) - 1);
|
||||||
|
memcpy(dirent.path, name, len);
|
||||||
|
dirent.path[len] = '\0';
|
||||||
|
dirent.type = MUFS_DIR;
|
||||||
|
|
||||||
|
dirent.tree.fs = fs;
|
||||||
|
dirent.tree.file_size = 0;
|
||||||
|
dirent.tree.root = 0;
|
||||||
|
dirent.tree.depth = 0;
|
||||||
|
|
||||||
|
if (!is_aligned(tree.file_size, fs->dev->log2_block_size) &&
|
||||||
|
write_dirent(&tree, tree.file_size, &dirent) > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (write_dirent(&tree, align_up(tree.file_size,
|
||||||
|
fs->dev->log2_block_size), &dirent) > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
12
source/fs/mufs/dir.h
Normal file
12
source/fs/mufs/dir.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct mufs_dentry {
|
||||||
|
uint8_t type;
|
||||||
|
uint32_t file_size;
|
||||||
|
uint32_t root;
|
||||||
|
uint8_t depth;
|
||||||
|
uint16_t path_len;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define MUFS_FILE BIT(0)
|
||||||
|
#define MUFS_DIR BIT(1)
|
|
@ -1,18 +1,20 @@
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <bitops.h>
|
#include <bitops.h>
|
||||||
#include <flash.h>
|
#include <flash.h>
|
||||||
|
#include <macros.h>
|
||||||
|
|
||||||
#include <fs/mufs.h>
|
#include <fs/mufs.h>
|
||||||
|
|
||||||
|
#include "dir.h"
|
||||||
|
|
||||||
struct mufs_super {
|
struct mufs_super {
|
||||||
char magic[4];
|
char magic[4];
|
||||||
uint32_t nblocks;
|
uint32_t nblocks;
|
||||||
uint32_t file_size;
|
struct mufs_dentry root;
|
||||||
uint32_t root;
|
|
||||||
uint8_t depth;
|
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
int mufs_mount(struct mufs *fs, struct flash_dev *dev)
|
int mufs_mount(struct mufs *fs, struct flash_dev *dev)
|
||||||
|
@ -32,9 +34,11 @@ int mufs_mount(struct mufs *fs, struct flash_dev *dev)
|
||||||
fs->nblocks = super.nblocks;
|
fs->nblocks = super.nblocks;
|
||||||
fs->log2_nentries = fs->dev->log2_block_size - ilog2(sizeof(uint32_t));
|
fs->log2_nentries = fs->dev->log2_block_size - ilog2(sizeof(uint32_t));
|
||||||
|
|
||||||
fs->root.file_size = super.file_size;
|
fs->root.fs = fs;
|
||||||
fs->root.root = super.root;
|
fs->root.va = offsetof(struct mufs_super, root) + 1;
|
||||||
fs->root.depth = super.depth;
|
fs->root.file_size = super.root.file_size;
|
||||||
|
fs->root.root = super.root.root;
|
||||||
|
fs->root.depth = super.root.depth;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -44,11 +48,14 @@ int mufs_format(struct flash_dev *dev)
|
||||||
struct mufs_super super;
|
struct mufs_super super;
|
||||||
|
|
||||||
memcpy(super.magic, "mufs", 4);
|
memcpy(super.magic, "mufs", 4);
|
||||||
|
|
||||||
super.nblocks = flash_get_capacity(dev) >> dev->log2_block_size;
|
super.nblocks = flash_get_capacity(dev) >> dev->log2_block_size;
|
||||||
|
|
||||||
super.file_size = 0;
|
super.root.type = MUFS_DIR;
|
||||||
super.root = 0;
|
super.root.file_size = 0;
|
||||||
super.depth = 0;
|
super.root.root = 0;
|
||||||
|
super.root.depth = 0;
|
||||||
|
super.root.path_len = 0;
|
||||||
|
|
||||||
if (flash_write(dev, 0, &super, sizeof super) == 0)
|
if (flash_write(dev, 0, &super, sizeof super) == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -16,10 +16,14 @@
|
||||||
|
|
||||||
static void do_mufs_mount(const char *s);
|
static void do_mufs_mount(const char *s);
|
||||||
static void do_mufs_format(const char *s);
|
static void do_mufs_format(const char *s);
|
||||||
|
static void do_mufs_mkdir(const char *s);
|
||||||
|
static void do_mufs_ls(const char *s);
|
||||||
|
|
||||||
static struct cmd mufs_cmds[] = {
|
static struct cmd mufs_cmds[] = {
|
||||||
{ "mount", do_mufs_mount },
|
{ "mount", do_mufs_mount },
|
||||||
{ "format", do_mufs_format },
|
{ "format", do_mufs_format },
|
||||||
|
{ "mkdir", do_mufs_mkdir },
|
||||||
|
{ "ls", do_mufs_ls },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,6 +43,9 @@ static void do_mufs_mount(const char *s)
|
||||||
fprintf(stderr, "error: unable to mount the filesystem.\n");
|
fprintf(stderr, "error: unable to mount the filesystem.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("log2_nentries=%u\n", mufs.log2_nentries);
|
||||||
|
printf("nentries=%u\n", UINT32_C(1) << mufs.log2_nentries);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_mufs_format(const char *s)
|
static void do_mufs_format(const char *s)
|
||||||
|
@ -56,6 +63,31 @@ static void do_mufs_format(const char *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void do_mufs_mkdir(const char *s)
|
||||||
|
{
|
||||||
|
if (mufs_mkdir(&mufs, s) < 0) {
|
||||||
|
fprintf(stderr, "error: unable to create the directory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_mufs_ls(const char *s)
|
||||||
|
{
|
||||||
|
struct mufs_dirent ent;
|
||||||
|
struct mufs_dir *dir;
|
||||||
|
|
||||||
|
if (!(dir = mufs_opendir(&mufs, s))) {
|
||||||
|
fprintf(stderr, "error: unable to open the directory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (mufs_readdir(dir, &ent) == 0) {
|
||||||
|
printf("%s\n", ent.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
mufs_closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
void do_mufs_cmd(const char *line)
|
void do_mufs_cmd(const char *line)
|
||||||
{
|
{
|
||||||
cmd_exec(mufs_cmds, line);
|
cmd_exec(mufs_cmds, line);
|
||||||
|
|
Loading…
Add table
Reference in a new issue