]> git.neil.brown.name Git - lafs-utils.git/commitdiff
Add name creation in directories, and implement 'store'
authorNeilBrown <neilb@suse.de>
Fri, 25 Mar 2011 21:33:27 +0000 (08:33 +1100)
committerNeilBrown <neilb@suse.de>
Fri, 25 Mar 2011 21:33:27 +0000 (08:33 +1100)
Signed-off-by: NeilBrown <neilb@suse.de>
include/lafs/lafs.h
lib/lafs_dir_add.c [new file with mode: 0644]
tools/lafs.c

index f2369110ebfe8cc0df3a620192fcee2a9a14fbd6..bee11fff4a0b8e962e1f8900be18cf0c709693c4 100644 (file)
@@ -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 <dirent.h>
+
+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 (file)
index 0000000..2641f36
--- /dev/null
@@ -0,0 +1,104 @@
+#include <string.h>
+#include <lafs/lafs.h>
+#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<<psz);
+       return space;
+}
+
+
+int lafs_dir_add(struct lafs_ino *dir, char *name, u32 inum, int type)
+{
+       /* lookup a name and return ino number, or 0 if not found */
+       struct lafs_dblk *db, *new;
+       u32 hash, newhash;
+       int chainoffset = 0;
+       int len = strlen(name);
+       int rv;
+       struct dirheader *dh;
+       char *n1, *n2;
+
+       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) {
+                       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;
+}
index 94c2ee942c9c13618975f3295462cf007a85fd23..dc62aa74fbe7b53b27c02de4c71ee201e6e80418 100644 (file)
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <getopt.h>
 #include <stdio.h>
+#include <errno.h>
 #include <readline/readline.h>
 #include <readline/history.h>
 #include <lafs/lafs.h>
@@ -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 ******/