From 8fc5cc8eea48e18af3afd289a472c4498619457b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 21 Mar 2011 13:37:05 +1100 Subject: [PATCH] Add support for internal path lookup Also auto-completion of 'internal' path names. Signed-off-by: NeilBrown --- include/lafs/lafs.h | 3 ++ lib/lafs_dir_lookup.c | 40 ++++++++++++++++++ lib/lafs_lookup_path.c | 30 +++++++++++++ tools/lafs.c | 95 +++++++++++++++++++++++++++++++++++------- 4 files changed, 153 insertions(+), 15 deletions(-) create mode 100644 lib/lafs_dir_lookup.c create mode 100644 lib/lafs_lookup_path.c diff --git a/include/lafs/lafs.h b/include/lafs/lafs.h index 6e5f3c5..926c13f 100644 --- a/include/lafs/lafs.h +++ b/include/lafs/lafs.h @@ -92,6 +92,9 @@ uint64_t lafs_leaf_lookup(unsigned char *buf, int len, u32 startaddr, u32 target, u32 *nextp); struct lafs_iblk *lafs_leaf_find(struct lafs_ino *inode, u32 addr, int adopt, u32 *next); +u32 lafs_dir_lookup(struct lafs_ino *dir, char *name, int len); +struct lafs_ino *lafs_lookup_path(struct lafs_ino *root, struct lafs_ino *cwd, + char *path); diff --git a/lib/lafs_dir_lookup.c b/lib/lafs_dir_lookup.c new file mode 100644 index 0000000..c8b0796 --- /dev/null +++ b/lib/lafs_dir_lookup.c @@ -0,0 +1,40 @@ +#include +#include +#include "internal.h" + +u32 lafs_dir_lookup(struct lafs_ino *dir, char *name, int len) +{ + /* lookup a name and return ino number, or 0 if not found */ + struct lafs_dblk *db; + u32 hash; + + hash = lafs_hash_name(dir->md.file.seed, len, name); + + while (1) { + u32 bnum; + int found; + u8 piece; + struct dir_ent de; + bnum = lafs_find_next(dir, hash+1); + if (bnum == LAFS_NOBLOCK) + bnum = 0; + + db = lafs_dblk(dir, bnum); + if (!db || + lafs_load_dblk(db)) + return 0; + + found = lafs_dir_find(db->b.data, dir->fs->blockbits-8, + dir->md.file.seed, + hash, &piece); + if (!found) + return 0; + lafs_dir_extract(db->b.data, dir->fs->blockbits-8, + &de, piece, NULL); + if (de.target && + de.nlen == len && + strncmp(de.name, name, len) == 0) + return de.target; + hash++; + } +} diff --git a/lib/lafs_lookup_path.c b/lib/lafs_lookup_path.c new file mode 100644 index 0000000..cf29cb6 --- /dev/null +++ b/lib/lafs_lookup_path.c @@ -0,0 +1,30 @@ +#include + +struct lafs_ino *lafs_lookup_path(struct lafs_ino *root, struct lafs_ino *cwd, + char *path) +{ + if (!path) + return cwd; + if (*path == '/') { + cwd = root; + while (*path == '/') + path++; + } + + while (cwd && *path) { + char *p = path; + int len; + u32 inum; + while (*path && *path != '/') + path++; + len = path - p; + while (*path == '/') + path++; + + inum = lafs_dir_lookup(cwd, p, len); + if (!inum) + return NULL; + cwd = lafs_get_inode(cwd->filesys, inum); + } + return cwd; +} diff --git a/tools/lafs.c b/tools/lafs.c index 94f3563..18c29db 100644 --- a/tools/lafs.c +++ b/tools/lafs.c @@ -52,6 +52,8 @@ struct state { int verbose; }; +static struct state *gen_state; + /* Every command can have arguments, both positional and * named. * Named arguments are specified with a leading hyphen, though @@ -390,6 +392,7 @@ static void interact(void) asprintf(&hist, "%s/.lafs_history", home); read_history(hist); + gen_state = &st; while (!st.done) { char *line = readline("LaFS: "); @@ -548,6 +551,49 @@ static char *choice_gen(const char *prefix, int state) return NULL; } +static char *internal_gen(const char *prefix, int state) +{ + static char *cp; + static char *pre = NULL; + static struct lafs_ino *inode; + static u32 index; + + u32 inum; + int type; + char name[257]; + + if (gen_state->lafs->ss.root == 0) { + rl_attempted_completion_over = 1; + return NULL; + } + if (state == 0) { + if (pre) + free(pre); + pre = strdup(prefix); + cp = pre + strlen(pre); + while (cp > pre && cp[-1] != '/') + cp--; + prefix = cp; + while (cp > pre && cp[-1] == '/') + cp--; + cp[0] = 0; + /*pre is the directory, prefix is the component prefix */ + inode = lafs_get_itable(gen_state->lafs); + inode = lafs_get_inode(inode, 2); + inode = lafs_lookup_path(inode, inode, pre); + index = -1; + } else { + if (index + 1 == 0) { + rl_attempted_completion_over = 1; + return NULL; + } + } + if (lafs_dir_next(inode, &index, name, &inum, &type) == 1) + return strdup(name); + + rl_attempted_completion_over = 1; + return NULL; +} /* * This is the brains of the completion handler. * We parse the line-so-far to determine way options have already @@ -616,6 +662,9 @@ static char **complete_in_context(const char *prefix, int start, int end) matches = rl_completion_matches( prefix, rl_filename_completion_function); break; + case internal: + matches = rl_completion_matches(prefix, internal_gen); + break; case choice: gen_options = args[p].options; matches = rl_completion_matches( @@ -1208,36 +1257,40 @@ static struct args args_show_inode[] = { }; static void c_show_inode(struct state *st, void **args) { - int ino; struct lafs_ino *inode; if (!args[2]) { printf("show inode: please give file name or inode number\n"); return; } + if (st->lafs->ss.root == 0) { + printf("show inode: filesytem not ready\n"); + return; + } + inode = lafs_get_itable(st->lafs); if (args[3]) { char *inostr = args[3]; char *endp; - ino = strtoul(inostr, &endp, 10); + int ino = strtoul(inostr, &endp, 10); if (endp == inostr || *endp) { printf("show inode: %s is not a valid inode number\n", inostr); return; } + if (ino) + inode = lafs_get_inode(inode, ino); + if (!inode) + printf("show inode: cannot find inode %d\n",ino); } else { - /* For now, path lookup always finds '0' */ - ino = 0; - } - if (st->lafs->ss.root == 0) { - printf("show inode: filesytem not ready\n"); - return; + char *path = args[2]; + inode = lafs_get_inode(inode, 2); + inode = lafs_lookup_path(inode, inode, path); + + if (!inode) { + printf("show inode: cannot find inode for %s\n", path); + return; + } } - inode = lafs_get_itable(st->lafs); - if (ino) - inode = lafs_get_inode(inode, ino); - if (inode) - lafs_print_inode(inode); - else - printf("show inode: cannot find inode %d\n",ino); + lafs_print_inode(inode); } /****** SHOW DEVICE ******/ @@ -1445,6 +1498,7 @@ static void c_ls(struct state *st, void **args) u32 inum; int type; int col; + char *path = args[1]; if (st->lafs->ss.root == 0) { printf("ls: filesytem not ready\n"); @@ -1452,7 +1506,18 @@ static void c_ls(struct state *st, void **args) } ino = lafs_get_itable(st->lafs); ino = lafs_get_inode(ino, 2); + if (path) + ino = lafs_lookup_path(ino, ino, path); + if (!ino) { + printf("ls: cannot find inode for %s\n", path?:"/"); + return; + } + + if (ino->type != TypeDir) { + printf("ls: %s exists but is not a directory\n", path); + return; + } col = 0; while (lafs_dir_next(ino, &index, name, &inum, &type) == 1) { if (args[2]) { -- 2.39.5