Source code for the Trusted Boot Module.
 
 
 
tbm-mcu/source/fs/mufs/dir.c

303 lines
5.7 KiB

#include <stddef.h>
#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 "path.h"
#include "tree.h"
struct mufs_dir {
struct mufs *fs;
struct mufs_tree *tree;
uint32_t va;
};
char *mufs_abspath(const char *path)
{
char *s, *p, *next, *prev;
if (!(s = malloc(strlen(path) + 2)))
return NULL;
strcpy(s, path);
for (p = s, next = p + strcspn(p, "/"); *p != '\0'; next = p + strcspn(p, "/")) {
char c = *next;
*next = '\0';
if (*p == '\0' || strcmp(p, ".") == 0) {
memmove(p, next + 1, strlen(next + 1) + 1);
continue;
}
if (strcmp(p, "..") == 0) {
if (!(prev = strrchr(s, '/'))) {
memmove(p, next + 1, strlen(next + 1) + 1);
continue;
}
*prev = '\0';
if (!(prev = strrchr(s, '/'))) {
memmove(s, next + 1, strlen(next + 1) + 1);
p = s;
continue;
}
memmove(prev + 1, next + 1, strlen(next + 1) + 1);
p = prev + 1;
continue;
}
*next = c;
p = next + 1;
}
memmove(s + 1, s, strlen(s) + 1);
*s = '/';
return s;
}
static struct mufs_dir *open_dirent(struct mufs *fs, struct mufs_dirent *entry)
{
struct mufs_dir *dir;
if (!(dir = malloc(sizeof *dir)))
return NULL;
dir->fs = fs;
dir->va = 0;
if (entry) {
if (!(dir->tree = malloc(sizeof *dir->tree)))
goto err_free_dir;
memcpy(dir->tree, &entry->tree, sizeof *dir->tree);
} else {
dir->tree = &fs->root;
}
return dir;
err_free_dir:
free(dir);
return NULL;
}
struct mufs_tree *resolve_path(struct mufs *fs, const char *path,
struct mufs_stat *stat)
{
struct mufs_dir *dir = NULL;
struct mufs_dirent entry, *found = NULL;
struct mufs_tree *tree = NULL;
char *s, *p, *end;
int ret;
if (!(s = mufs_abspath(path)))
return NULL;
if (strcmp(s, "/") == 0) {
tree = &fs->root;
if (stat) {
stat->type = MUFS_DIR;
stat->file_size = tree->file_size;
}
goto err_free_s;
}
for (p = s + 1; *p != '\0'; p = end) {
if (!(dir = open_dirent(fs, found)))
goto err_free_s;
end = p + strcspn(p, "/");
if (*end == '/')
*end++ = '\0';
while ((ret = mufs_readdir(dir, &entry)) == 0) {
if (strcmp(entry.path, p) != 0)
continue;
found = &entry;
break;
}
if (ret < 0)
goto err_closedir;
}
if (!dir)
goto err_free_s;
tree = dir->tree;
dir->tree = NULL;
if (stat) {
stat->type = entry.type;
stat->file_size = tree->file_size;
}
err_closedir:
mufs_closedir(dir);
err_free_s:
free(s);
return tree;
}
struct mufs_dir *mufs_opendir(struct mufs *fs, const char *path)
{
struct mufs_stat stat;
struct mufs_dir *dir;
if (!(dir = malloc(sizeof(*dir))))
return NULL;
dir->fs = fs;
if (!(dir->tree = resolve_path(fs, path, &stat)) || stat.type != MUFS_DIR)
goto err_free_dir;
dir->va = 0;
return dir;
err_free_dir:
free(dir);
return NULL;
}
void mufs_closedir(struct mufs_dir *dir)
{
if (!dir)
return;
if (dir->tree && dir->tree != &dir->fs->root)
free(dir->tree);
free(dir);
}
size_t read_dirent(struct mufs *fs, struct mufs_tree *tree,
struct mufs_dirent *dirent, uint32_t va)
{
struct flash_dev *dev = fs->dev;
char data[1 << dev->log2_block_size];
struct mufs_dentry *entry;
uint32_t offset;
offset = va & ((UINT32_C(1) << dev->log2_block_size) - 1);
va = align(va, dev->log2_block_size);
if (mufs_tree_read(tree, data, va, 1 << dev->log2_block_size) == 0)
return 0;
if (offset + sizeof *entry > (UINT32_C(1) << dev->log2_block_size))
return 0;
entry = (struct mufs_dentry *)(data + offset);
if (!entry->type)
return 0;
if (offset + sizeof *entry + entry->path_len >
(UINT32_C(1) << dev->log2_block_size))
return 0;
memcpy(dirent->path, data + offset + sizeof *entry, entry->path_len);
dirent->path[entry->path_len] = '\0';
dirent->type = entry->type;
if (mufs_lookup_page(tree, &dirent->tree.va, va) < 0)
return 0;
dirent->tree.fs = fs;
dirent->tree.va = (dirent->tree.va << dev->log2_block_size) + offset +
offsetof(struct mufs_dentry, tree);
dirent->tree.file_size = entry->tree.file_size;
dirent->tree.root = entry->tree.root;
dirent->tree.depth = entry->tree.depth;
return sizeof *entry + entry->path_len;
}
size_t write_dirent(struct mufs_tree *tree,
uint32_t va, struct mufs_dirent *dirent)
{
struct mufs *fs = tree->fs;
struct flash_dev *dev = fs->dev;
char data[1 << dev->log2_block_size];
struct mufs_dentry entry;
size_t size;
entry.type = dirent->type;
entry.tree.file_size = dirent->tree.file_size;
entry.tree.root = dirent->tree.root;
entry.tree.depth = dirent->tree.depth;
entry.path_len = strlen(dirent->path);
memcpy(data, &entry, sizeof entry);
memcpy(data + sizeof entry, dirent->path, entry.path_len);
size = sizeof entry + entry.path_len;
if (mufs_tree_write(tree, data, va, size) == 0)
return 0;
va += sizeof entry + entry.path_len;
tree->file_size = max(tree->file_size, va);
if (tree->file_size <= va && mufs_sync_tree(tree) < 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;
}
return -1;
}
int mufs_mkdir(struct mufs *fs, const char *path)
{
return mufs_mkpath(fs, path, MUFS_DIR);
}
int mufs_rmdir(struct mufs *fs, const char *path)
{
struct mufs_stat stat;
if (mufs_stat(fs, path, &stat) < 0)
return -1;
if (stat.type != MUFS_DIR || stat.file_size != 0)
return -1;
return mufs_rmpath(fs, path);
}