static int phoenixfs_getattr(const char *path, struct stat *stbuf) { struct file_record *fr; struct dir_record *dr; int rev; rev = parse_pathspec(xpath, path); build_xpath(openpath, xpath, rev); PHOENIXFS_DBG("getattr:: %s %d", openpath, rev); /* Try underlying FS */ if (lstat(openpath, stbuf) < 0) { /* Try fstree */ if (!(dr = find_dr(xpath))) { if (!(fr = find_fr(xpath, rev))) return -ENOENT; else { memset(stbuf, 0, sizeof(struct stat)); fill_stat(stbuf, fr); return 0; } } memset(stbuf, 0, sizeof(struct stat)); stbuf->st_mode = S_IFDIR | 0755; } return 0; }
void fstree_remove_file(const char *path) { struct dir_record *dr; struct vfile_record *vfr; uint16_t key = ~0; size_t length; char *filename; int rev; filename = split_basename(path, dirname); length = (size_t) strlen((char *) filename); key = compute_crc32(key, (const unsigned char *) filename, length); if (!(dr = find_dr(dirname))) { PHOENIXFS_DBG("fstree_remove_file:: missing %s", dirname); return; } if (!(vfr = find(dr->vroot, key, 0))) { PHOENIXFS_DBG("fstree_remove_file:: missing %s", filename); return; } for (rev = 0; ; rev++) { if (!vfr->history[rev]) break; free(vfr->history[rev]); } PHOENIXFS_DBG("fstree_remove_file:: %s", path); delete(dr->vroot, key); }
static int phoenixfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { DIR *dp; struct dirent *de; struct stat st; void *record; struct node *iter_root, *iter; struct vfile_record *vfr; struct dir_record *dr; register int i; dp = (DIR *) (uintptr_t) fi->fh; if (!(de = readdir(dp))) return -errno; /* Fill directories from backing FS */ do { /* Hide the .git directory, and enumerate only directories */ if (strcmp(de->d_name, ".git") && de->d_type == DT_DIR) { PHOENIXFS_DBG("readdir:: fs: %s", de->d_name); if (filler(buf, de->d_name, NULL, 0)) return -ENOMEM; } } while ((de = readdir(dp)) != NULL); /* Fill files from fstree */ if (!(dr = find_dr(path)) || !dr->vroot) { PHOENIXFS_DBG("readdir:: fstree: blank"); return 0; } iter_root = dr->vroot; iter = dr->vroot; /* Use only the leaves */ while (!iter->is_leaf) iter = iter->pointers[0]; while (1) { for (i = 0; i < iter->num_keys; i++) { if (!(record = find(iter_root, iter->keys[i], 0))) PHOENIXFS_DBG("readdir:: key listing issue"); vfr = (struct vfile_record *) record; fill_stat(&st, vfr->history[vfr->HEAD]); PHOENIXFS_DBG("readdir:: tree fill: %s", (const char *) vfr->name); if (filler(buf, (const char *) vfr->name, &st, 0)) return -ENOMEM; } if (iter->pointers && iter->pointers[BTREE_ORDER - 1] != NULL) iter = iter->pointers[BTREE_ORDER - 1]; else break; } return 0; }
void fstree_insert_update_file(const char *path, const char *follow) { struct dir_record *dr; struct vfile_record *vfr; struct file_record *fr, *new_fr; uint16_t key = ~0; char *filename; size_t length; filename = split_basename(path, dirname); if (!(dr = find_dr(dirname))) goto DR; else { length = (size_t) strlen((char *) filename); key = compute_crc32(key, (const unsigned char *) filename, length); if (!(vfr = find(dr->vroot, key, 0))) { PHOENIXFS_DBG("fstree_insert_update_file:: missing vfr: %s", filename); goto VFR; } else { if (vfr->HEAD >= 0) fr = vfr->history[vfr->HEAD]; else fr = NULL; goto FR; } } DR: dr = make_dr(dirname); insert_dr(dr); VFR: vfr = make_vfr(filename); insert_vfr(dr, vfr); FR: if (!(new_fr = make_fr(path, follow))) { PHOENIXFS_DBG("fstree_insert_update_file:: Can't make fr %s", path); return; } /* If content is present in the old fr, don't make a new fr */ if (fr && !memcmp(fr->sha1, new_fr->sha1, 20)) { PHOENIXFS_DBG("fstree_insert_update_file:: unmodified: %s", path); free(new_fr); return; } insert_fr(vfr, new_fr); }
struct vfile_record *find_vfr(const char *path) { uint16_t key = ~0; struct dir_record *dr; struct vfile_record *vfr; char *filename; size_t length; filename = split_basename(path, dirname); if (!(dr = find_dr(dirname)) || !dr->vroot) { PHOENIXFS_DBG("find_vfr:: not found %s", path); return NULL; } length = (size_t) strlen((char *) filename); key = compute_crc32(key, (const unsigned char *) filename, length); if (!(vfr = find(dr->vroot, key, 0))) { PHOENIXFS_DBG("find_vfr:: not found %s", path); return NULL; } PHOENIXFS_DBG("find_vfr:: found %s", path); return vfr; }
static int phoenixfs_opendir(const char *path, struct fuse_file_info *fi) { struct dir_record *dr; DIR *dp; PHOENIXFS_DBG("opendir:: %s", path); build_xpath(xpath, path, 0); /* Try underlying fs */ if (!(dp = opendir(xpath))) { /* Try fstree */ if (!(dr = find_dr(path))) return -ENOENT; else { /* Make the directory and open it */ mkdir(xpath, S_IRUSR | S_IWUSR | S_IXUSR); dp = opendir(xpath); } } fi->fh = (intptr_t) dp; return 0; }
static int phoenixfs_rename(const char *path, const char *newpath) { char xnewpath[PATH_MAX]; struct dir_record *dr; struct vfile_record *vfr, *new_vfr; char *filename, *newfilename; uint16_t key = ~0; size_t length; uint8_t start_rev, rev_nr; PHOENIXFS_DBG("rename:: %s to %s", path, newpath); build_xpath(xpath, path, 0); build_xpath(xnewpath, newpath, 0); if (rename(xpath, xnewpath) < 0) return -errno; /* Update fstree */ filename = split_basename(path, xpath); if (!(dr = find_dr(xpath))) { PHOENIXFS_DBG("rename:: Missing dr for %s", xpath); return 0; } /* Find the old vfr to copy out data from and remove */ length = (size_t) strlen((char *) filename); key = compute_crc32(key, (const unsigned char *) filename, length); if (!(vfr = find(dr->vroot, key, 0))) { PHOENIXFS_DBG("rename:: Missing vfr for %s", path); return 0; } /* Make a new vfr and copy out history from old vfr */ newfilename = split_basename(path, NULL); new_vfr = make_vfr(newfilename); /* Compute start_rev and rev_nr */ if (vfr->HEAD < 0) { start_rev = 0; rev_nr = 0; } else if (vfr->history[(vfr->HEAD + 1) % REV_TRUNCATE]) { /* History is full, and is probably wrapping around */ start_rev = (vfr->HEAD + 1) % REV_TRUNCATE; rev_nr = 20; } else { /* History is not completely filled */ start_rev = 0; rev_nr = vfr->HEAD + 1; } PHOENIXFS_DBG("rename:: copying %d revisions", rev_nr); while (start_rev < rev_nr) { new_vfr->history[start_rev] = vfr->history[start_rev]; start_rev = (start_rev + 1) % REV_TRUNCATE; } new_vfr->HEAD = rev_nr - 1; insert_vfr(dr, new_vfr); /* Remove old vfr */ dr->vroot = remove_entry(dr->vroot, key); return 0; }