|
|
|
#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"
|
|
|
|
|
|
|
|
int mufs_mkpath(struct mufs *fs, const char *path, unsigned type)
|
|
|
|
{
|
|
|
|
struct mufs_stat stat;
|
|
|
|
struct mufs_dirent dirent;
|
|
|
|
struct mufs_tree *tree;
|
|
|
|
size_t len;
|
|
|
|
char *s;
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
if (!path || *path == '\0')
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(s = mufs_abspath(path)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* TODO: already exists. */
|
|
|
|
if (resolve_path(fs, s, NULL)) {
|
|
|
|
free(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = strrchr(s, '/');
|
|
|
|
*name++ = '\0';
|
|
|
|
|
|
|
|
if (*s == '\0')
|
|
|
|
s = "/";
|
|
|
|
|
|
|
|
if (*name == '\0')
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(tree = resolve_path(fs, s, &stat)) || stat.type != MUFS_DIR)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
len = min(strlen(name), sizeof(dirent.path) - 1);
|
|
|
|
memcpy(dirent.path, name, len);
|
|
|
|
dirent.path[len] = '\0';
|
|
|
|
dirent.type = type;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int remove_page(struct mufs_tree *tree, uint32_t va)
|
|
|
|
{
|
|
|
|
struct mufs *fs = tree->fs;
|
|
|
|
struct flash_dev *dev = fs->dev;
|
|
|
|
uint32_t last_va, page;
|
|
|
|
|
|
|
|
last_va = align(tree->file_size - 1, dev->log2_block_size);
|
|
|
|
|
|
|
|
if (mufs_lookup_page(tree, &page, last_va) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
mufs_free_page(tree, va);
|
|
|
|
|
|
|
|
if (va != last_va) {
|
|
|
|
mufs_unmap_page(tree, last_va);
|
|
|
|
mufs_map_page(tree, va, page);
|
|
|
|
}
|
|
|
|
|
|
|
|
tree->file_size -= (UINT32_C(1) << dev->log2_block_size);
|
|
|
|
|
|
|
|
return mufs_sync_tree(tree);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mufs_rmpath(struct mufs *fs, const char *path)
|
|
|
|
{
|
|
|
|
struct flash_dev *dev = fs->dev;
|
|
|
|
char data[1 << dev->log2_block_size];
|
|
|
|
struct mufs_dentry *entry, *next;
|
|
|
|
struct mufs_tree *tree;
|
|
|
|
char *s;
|
|
|
|
uint32_t va, offset, len;
|
|
|
|
|
|
|
|
if (!(s = mufs_abspath(path)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(tree = resolve_path(fs, s, NULL))) {
|
|
|
|
free(s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset = tree->va & ((UINT32_C(1) << dev->log2_block_size) - 1);
|
|
|
|
va = align(tree->va, dev->log2_block_size);
|
|
|
|
|
|
|
|
if (mufs_tree_read(tree, data, va, 1 << dev->log2_block_size) == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
entry = (struct mufs_dentry *)(data + offset);
|
|
|
|
len = sizeof *entry + entry->path_len;
|
|
|
|
next = (struct mufs_dentry *)(data + offset + len);
|
|
|
|
|
|
|
|
if (!offset && (len == (UINT32_C(1) << dev->log2_block_size) ||
|
|
|
|
!next->type))
|
|
|
|
return remove_page(tree, va);
|
|
|
|
|
|
|
|
memmove(data + offset, data + offset + len,
|
|
|
|
(UINT32_C(1) << dev->log2_block_size) - offset - len);
|
|
|
|
|
|
|
|
if (mufs_tree_write(tree, data, va, 1 << dev->log2_block_size) == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mufs_stat(struct mufs *fs, const char *path, struct mufs_stat *stat)
|
|
|
|
{
|
|
|
|
if (!resolve_path(fs, path, stat))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|