#include #include #include #include #include #include #include #include #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 *mufs_opendirent(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_dir *dir; struct mufs_dirent entry; struct mufs_tree *tree; char *s, *p, *end; int ret; if (!(s = mufs_abspath(path))) return NULL; if (strcmp(s, "/") == 0) return &fs->root; if (!(dir = mufs_opendirent(fs, NULL))) goto err_free_s; for (p = s + 1; *p != '\0'; p = end) { end = p + strcspn(p, "/"); if (*end == '/') *end++ = '\0'; while ((ret = mufs_readdir(dir, &entry)) == 0) { if (strcmp(entry.path, p) != 0) continue; mufs_closedir(dir); if (!(dir = mufs_opendirent(fs, &entry))) goto err_free_s; break; } if (ret < 0) goto err_close_dir; } tree = dir->tree; mufs_closedir(dir); return tree; err_close_dir: mufs_closedir(dir); err_free_s: free(s); return NULL; } 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; if (!(dir->tree = resolve_path(fs, path))) 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; 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); }