#include #include #include #include #include #include #include #include #include "dir.h" #include "path.h" #include "tree.h" int mufs_mkpath(struct mufs *fs, const char *path, struct mufs_tree *subtree, unsigned type) { struct mufs_stat stat; struct mufs_dirent dirent; struct mufs_tree *tree; size_t len; char *s; char *name; 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; memset(&dirent, 0, sizeof dirent); len = min(strlen(name), sizeof(dirent.path) - 1); memcpy(dirent.path, name, len); dirent.path[len] = '\0'; dirent.type = type; dirent.tree.fs = fs; if (subtree) { dirent.tree.file_size = subtree->file_size; dirent.tree.root = subtree->root; dirent.tree.depth = subtree->depth; } tree->file_size = find_dirent_size(fs, tree, tree->file_size); 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 = last_va; 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_dirent ent; struct mufs_tree *tree; struct mufs_dir *dir; char *s, *name; uint32_t va, offset, len; int ret; if (!(s = mufs_abspath(path))) return -1; name = strrchr(s, '/'); *name++ = '\0'; if (!(tree = resolve_path(fs, s, NULL))) goto err_free_s; if (!(dir = mufs_opendir(fs, s))) goto err_free_s; for (va = dir->va; (ret = mufs_readdir(dir, &ent)) == 0; va = dir->va) { if (strcmp(ent.path, name) == 0) break; } mufs_closedir(dir); if (ret < 0) goto err_free_s; 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 -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; free(s); return 0; err_free_s: free(s); return -1; } int mufs_stat(struct mufs *fs, const char *path, struct mufs_stat *stat) { if (!resolve_path(fs, path, stat)) return -1; return 0; } int mufs_rename(struct mufs *fs, const char *old, const char *new) { struct mufs_stat stat; struct mufs_dirent dirent; struct mufs_tree *tree; size_t len; char *full_old, *full_new; char *name; int ret = -1; if (!(full_new = mufs_abspath(new))) return -1; if (resolve_path(fs, full_new, NULL)) goto err_free_new; if (!(full_old = mufs_abspath(old))) goto err_free_new; name = strrchr(full_new, '/'); *name++ = '\0'; if (*full_new == '\0') full_new = "/"; if (*name == '\0') goto err_free_old; if (!(tree = resolve_path(fs, full_old, &stat))) goto err_free_old; len = min(strlen(name), sizeof(dirent.path) - 1); memcpy(dirent.path, name, len); dirent.path[len] = '\0'; dirent.type = stat.type; dirent.tree.fs = fs; dirent.tree.file_size = tree->file_size; dirent.tree.root = tree->root; dirent.tree.depth = tree->depth; if (!is_aligned(tree->file_size, fs->dev->log2_block_size) && write_dirent(tree, tree->file_size, &dirent) > 0) goto err_free_old; if (write_dirent(tree, align_up(tree->file_size, fs->dev->log2_block_size), &dirent) > 0) goto err_free_old; if (mufs_rmpath(fs, full_old) < 0) goto err_free_old; ret = 0; err_free_old: free(full_old); err_free_new: free(full_new); return ret; }