From 8955396a12edc0e9b3f89f2eacc294b6e37f3a25 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 26 Mar 2011 08:33:27 +1100 Subject: [PATCH] Add name creation in directories, and implement 'store' Signed-off-by: NeilBrown --- include/lafs/lafs.h | 16 +++++++ lib/lafs_dir_add.c | 104 ++++++++++++++++++++++++++++++++++++++++++++ tools/lafs.c | 63 +++++++++++++++++++++++++-- 3 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 lib/lafs_dir_add.c diff --git a/include/lafs/lafs.h b/include/lafs/lafs.h index f236911..bee11ff 100644 --- a/include/lafs/lafs.h +++ b/include/lafs/lafs.h @@ -100,6 +100,7 @@ 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, char **remainder); int lafs_imap_alloc(struct lafs_ino *imap); +int lafs_dir_add(struct lafs_ino *dir, char *name, u32 inum, int type); @@ -176,3 +177,18 @@ virttophys(struct lafs *fs, loff_t virt, int *devp, loff_t *sectp) virt += dv->segment_offset; *sectp = virt; } + +#include + +static inline int lafs_dt_type(struct lafs_ino *ino) +{ + if (ino->type < TypeBase) + return 0; + switch(ino->type) { + default: return 0; + case TypeFile: return DT_REG; + case TypeDir: return DT_DIR; + case TypeSymlink: return DT_LNK; + case TypeSpecial: return ino->md.file.mode >> 12; + } +} diff --git a/lib/lafs_dir_add.c b/lib/lafs_dir_add.c new file mode 100644 index 0000000..2641f36 --- /dev/null +++ b/lib/lafs_dir_add.c @@ -0,0 +1,104 @@ +#include +#include +#include "internal.h" + +static inline int space_needed(int len, int chainoffset, int psz) +{ + int space; + space = len + (chainoffset > 255 ? 4 : chainoffset > 1 ? 1 : 0); + space += offsetof(struct dirpiece, name); + space = DIV_ROUND_UP(space, 1<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) { + 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 0; /* already exists */ + if (de.target) { + /* chain forwards */ + hash++; + chainoffset++; + continue; + } + } + /* This hash value is free. */ + break; + } + rv = lafs_dir_add_ent(db->b.data, dir->fs->blockbits-8, + name, len, inum, type, + dir->md.file.seed, + hash, chainoffset); + BUG_ON(rv < 0); + if (rv == 1) { + lafs_sched_blk(&db->b); + return 1; + } + /* didn't fit - need to split */ + dh = (struct dirheader*)(db->b.data); + if (dh->freepieces >= space_needed(len, chainoffset, + dir->fs->blockbits-8)) { + char *tmp = malloc(dir->fs->blocksize); + lafs_dir_repack(db->b.data, dir->fs->blockbits-8, + tmp, dir->md.file.seed, 0); + rv = lafs_dir_add_ent(tmp, dir->fs->blockbits-8, + name, len, inum, type, + dir->md.file.seed, + hash, chainoffset); + if (rv == 1) { + memcpy(db->b.data, tmp, dir->fs->blocksize); + free(tmp); + lafs_sched_blk(&db->b); + return 1; + } + free(tmp); + } + /* Really doesn't fit, need to split */ + n1 = malloc(dir->fs->blocksize); + n2 = malloc(dir->fs->blocksize); + lafs_dir_split(db->b.data, dir->fs->blockbits-8, n1, n2, + name, inum, type, &newhash, + dir->md.file.seed, hash, chainoffset); + memcpy(db->b.data, n2, dir->fs->blocksize); + new = lafs_dblk(dir, newhash+1); + memcpy(new->b.data, n1, dir->fs->blocksize); + free(n1); + free(n2); + lafs_sched_blk(&db->b); + lafs_sched_blk(&new->b); + return 1; +} diff --git a/tools/lafs.c b/tools/lafs.c index 94c2ee9..dc62aa7 100644 --- a/tools/lafs.c +++ b/tools/lafs.c @@ -33,9 +33,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -1477,12 +1479,65 @@ static void c_store(struct state *st, void **args) { char *from = args[1]; char *to = args[2]; - if (!from) + struct lafs_ino *dir, *fs, *imfile, *inode; + char *tail = NULL; + int fd; + loff_t bnum; + u32 inum; + + if (!from) { printf("ERROR: Source file is missing\n"); - else if (!to) + return; + } + if (!to) { printf("ERROR: destination file name is missing\n"); - else - printf("Oh how I wish I could copy %s to %s\n", from, to); + return; + } + + fs = lafs_get_itable(st->lafs); + dir = lafs_get_inode(fs, 2); + dir = lafs_lookup_path(dir, dir, to, &tail); + if (!dir) { + printf("store: lookup error in %s\n",to); + return; + } + if (tail == NULL) { + printf("store: %s already exists\n", to); + return; + } + if (dir->type != TypeDir) { + *tail = 0; + printf("store: non-directory found at %s\n", to); + return; + } + if (strchr(tail, '/') != NULL) { + printf("store: non-final name does not exist: %s\n", tail); + return; + } + + fd = open(from, O_RDONLY); + if (fd < 0) { + printf("store: Cannot open %s: %s\n", from, strerror(errno)); + return; + } + + imfile = lafs_get_inode(fs, 1); + inum = lafs_imap_alloc(imfile); + inode = lafs_add_inode(fs, inum, TypeFile); + lafs_dir_add(dir, tail, inum, lafs_dt_type(inode)); + + bnum = 0; + while(1) { + struct lafs_dblk *db = lafs_dblk(inode, bnum); + int n = read(fd, db->b.data, st->lafs->blocksize); + if (n <= 0) + break; + inode->md.file.size = (bnum << st->lafs->blockbits) + n; + db->b.flags |= B_Valid; + lafs_dirty_blk(db); + bnum++; + } + printf("Created %s as inode %d in %d\n", tail, inum, dir->inum); } /****** LS ******/ -- 2.39.5