int build_xpath(char *xpath, const char *path, int rev) { struct file_record *fr; char sha1_digest[40]; if (!rev) { /* Search on FS */ strcpy(xpath, ROOTENV->fsback); strcat(xpath, path); return 0; } if (!(fr = find_fr(path, rev))) { PHOENIXFS_DBG("build_xpath:: missing: %s@%d", path, rev); /* Might be a directory; copy and give to caller */ strcpy(xpath, path); return -1; } print_sha1(sha1_digest, fr->sha1); sprintf(xpath, "%s/.git/loose/%s", ROOTENV->fsback, sha1_digest); if (access(xpath, F_OK) < 0) { /* Try extracting from packfile */ sprintf(xpath, "%s/.git/loose", ROOTENV->fsback); if (unpack_entry(fr->sha1, xpath) < 0) return -1; else PHOENIXFS_DBG("open:: pack %s", sha1_digest); } else PHOENIXFS_DBG("open:: loose %s", sha1_digest); return 0; }
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; }
static int phoenixfs_open(const char *path, struct fuse_file_info *fi) { int rev, fd; FILE *infile, *fsfile; char fspath[PATH_MAX]; struct file_record *fr; char sha1_digest[40]; rev = parse_pathspec(xpath, path); build_xpath(fspath, xpath, 0); /* Skip zinflate for entries not in fstree */ if (!(fr = find_fr(xpath, rev))) goto END; /* Build openpath by hand */ print_sha1(sha1_digest, fr->sha1); sprintf(openpath, "%s/.git/loose/%s", ROOTENV->fsback, sha1_digest); if (access(openpath, F_OK) < 0) { /* Try extracting from packfile */ sprintf(xpath, "%s/.git/loose", ROOTENV->fsback); if (unpack_entry(fr->sha1, xpath) < 0) return -ENOENT; else PHOENIXFS_DBG("open:: pack %s", sha1_digest); } else PHOENIXFS_DBG("open:: loose %s", sha1_digest); /* zinflate openpath onto fspath */ PHOENIXFS_DBG("open:: zinflate %s onto %s", sha1_digest, fspath); if (!(infile = fopen(openpath, "rb")) || !(fsfile = fopen(fspath, "wb+"))) return -errno; if (zinflate(infile, fsfile) != Z_OK) PHOENIXFS_DBG("open:: zinflate issue"); fclose(infile); fclose(fsfile); END: if ((fd = open(fspath, fi->flags)) < 0) return -errno; fi->fh = fd; return 0; }
static int phoenixfs_release(const char *path, struct fuse_file_info *fi) { struct file_record *fr; FILE *infile, *outfile; struct stat st; unsigned char sha1[20]; char sha1_digest[40]; char outfilename[40]; char inpath[PATH_MAX]; char outpath[PATH_MAX]; int rev, ret; pthread_mutex_lock(&phoenixfs_mutexlock); /* Don't recursively backup history */ if ((rev = parse_pathspec(xpath, path))) { PHOENIXFS_DBG("release:: history: %s", path); /* Inflate the original version back onto the filesystem */ if (!(fr = find_fr(xpath, 0))) { PHOENIXFS_DBG("release:: Can't find revision 0!"); pthread_mutex_unlock(&phoenixfs_mutexlock); return 0; } print_sha1(sha1_digest, fr->sha1); sprintf(inpath, "%s/.git/loose/%s", ROOTENV->fsback, sha1_digest); build_xpath(outpath, xpath, 0); if (!(infile = fopen(inpath, "rb")) || !(outfile = fopen(outpath, "wb+"))) { pthread_mutex_unlock(&phoenixfs_mutexlock); return -errno; } PHOENIXFS_DBG("release:: history: zinflate %s onto %s", sha1_digest, outpath); rewind(infile); rewind(outfile); if (zinflate(infile, outfile) != Z_OK) PHOENIXFS_DBG("release:: zinflate issue"); fflush(outfile); fclose(infile); fclose(outfile); if (close(fi->fh) < 0) { PHOENIXFS_DBG("release:: can't really close"); pthread_mutex_unlock(&phoenixfs_mutexlock); return -errno; } pthread_mutex_unlock(&phoenixfs_mutexlock); return 0; } /* Attempt to create a backup */ build_xpath(xpath, path, 0); if (!(infile = fopen(xpath, "rb")) || (lstat(xpath, &st) < 0)) { pthread_mutex_unlock(&phoenixfs_mutexlock); return -errno; } if ((ret = sha1_file(infile, st.st_size, sha1)) < 0) { fclose(infile); pthread_mutex_unlock(&phoenixfs_mutexlock); return ret; } print_sha1(outfilename, sha1); sprintf(outpath, "%s/.git/loose/%s", ROOTENV->fsback, outfilename); if (!access(outpath, F_OK)) { /* SHA1 match; don't overwrite file as an optimization */ PHOENIXFS_DBG("release:: not overwriting: %s", outpath); goto END; } if (!(outfile = fopen(outpath, "wb"))) { fclose(infile); pthread_mutex_unlock(&phoenixfs_mutexlock); return -errno; } /* Rewind and seek back */ rewind(infile); PHOENIXFS_DBG("release:: zdeflate %s onto %s", xpath, outfilename); if (zdeflate(infile, outfile, -1) != Z_OK) PHOENIXFS_DBG("release:: zdeflate issue"); mark_for_packing(sha1, st.st_size); fclose(outfile); END: fclose(infile); if (close(fi->fh) < 0) { PHOENIXFS_DBG("release:: can't really close"); return -errno; } /* Update the fstree */ fstree_insert_update_file(path, NULL); pthread_mutex_unlock(&phoenixfs_mutexlock); return 0; }