int share_file_copy_cb(SHFL *src_file, SHFL *dest_file) { shpeer_t *src_peer = shfs_inode_peer(src_file); int err; if (0 == strcmp(src_peer->label, "file")) { char path[PATH_MAX+1]; /* set link to local-disk path. */ sprintf(path, "%s", shfs_inode_path(src_file)); err = shfs_ext_set(src_file, path); if (err) return (err); } /* perform file copy */ err = shfs_file_copy(src_file, dest_file); if (err) { fprintf(sharetool_fout, "%s: error copying \"%s\" to \"%s\": %s [sherr %d].\n", process_path, shfs_filename(src_file), shfs_filename(dest_file), sherrstr(err), err); return (err); } if (!(run_flags & PFLAG_QUIET) && (run_flags & PFLAG_VERBOSE)) { fprintf(sharetool_fout, "%s: %s \"%s\" copied to %s \"%s\".\n", process_path, shfs_type_str(shfs_type(src_file)), shfs_filename(src_file), shfs_type_str(shfs_type(dest_file)), shfs_filename(dest_file)); } return (0); }
shfs_ino_t *shfs_rev_get(shfs_ino_t *repo, shkey_t *rev_key) { shfs_ino_t *rev; if (shfs_type(repo) == SHINODE_FILE) repo = shfs_inode(repo, NULL, SHINODE_REPOSITORY); if (shfs_type(repo) != SHINODE_REPOSITORY) return (NULL); if (shkey_cmp(rev_key, ashkey_blank())) return (NULL); return (shfs_inode(repo, (char *)shkey_hex(rev_key), SHINODE_REVISION)); }
int shfs_rev_init(shfs_ino_t *file) { shfs_attr_t attr; shfs_ino_t *repo; shfs_ino_t *head; shfs_ino_t *rev; shfs_ino_t *tag; int err; if (shfs_type(file) != SHINODE_FILE) return (SHERR_OPNOTSUPP); attr = shfs_attr(file); if (attr & SHATTR_VER) { /* inode is already initialized for repository. */ return (0); } /* commit current data content */ err = shfs_rev_commit(file, &rev); if (err) return (err); /* set initial description */ shfs_rev_desc_set(rev, "initial revision"); /* create master branch */ err = shfs_rev_branch(file, "master", rev); if (err) return (err); return (0); }
/** reference a revision by name */ int shfs_rev_ref(shfs_ino_t *file, char *group, char *name, shfs_ino_t *rev) { shfs_ino_t *branch; shfs_ino_t *ref; shkey_t *ref_key; char buf[SHFS_PATH_MAX]; int err; if (!rev) { return (SHERR_INVAL); } if (shfs_type(rev) != SHINODE_REVISION) return (SHERR_INVAL); ref_key = shkey_hexgen(shfs_filename(rev)); if (!ref_key) return (SHERR_IO); if (shkey_cmp(ref_key, ashkey_blank())) { /* not a revision (filename has no hex key) */ shkey_free(&ref_key); return (SHERR_INVAL); } memset(buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf)-1, "%s/%s", group, name); err = shfs_obj_set(file, buf, ref_key); shkey_free(&ref_key); if (err) return (err); return (0); }
int shfs_ref_get(shfs_ino_t *file, shfs_t **ref_fs_p, shfs_ino_t **ref_p) { shfs_ino_t *ref; shfs_ino_t *parent; shpeer_t *peer; shfs_t *fs; shkey_t *hier; shbuf_t *buff; char path[SHFS_PATH_MAX]; int hier_cnt; int err; int i; *ref_p = NULL; *ref_fs_p = NULL; if (!file || !file->tree) return (SHERR_INVAL); buff = shbuf_init(); err = _shfs_ref_raw_read(file, buff); if (err) return (err); peer = (shpeer_t *)shbuf_data(buff); hier = (shkey_t *)(shbuf_data(buff) + sizeof(shpeer_t)); fs = shfs_init(peer); if (!fs) return (SHERR_IO); memset(path, 0, sizeof(path)); strcpy(path, "/"); ref = fs->fsbase_ino; for (i = SHFS_MAX_REFERENCE_HIERARCHY - 1; i >= 0; i--) { if (shkey_cmp(&hier[i], ashkey_blank())) continue; if (shkey_cmp(&hier[i], shfs_token(file->tree->fsbase_ino))) continue; ref = shfs_inode_load(ref, &hier[i]); if (!ref) { shfs_free(&fs); return (SHERR_NOENT); } if (shfs_type(ref) == SHINODE_DIRECTORY) strncat(path, "/", SHFS_PATH_MAX - strlen(path) - 1); strncat(path, shfs_filename(ref), SHFS_PATH_MAX - strlen(path) - 1); } shbuf_free(&buff); *ref_p = ref; *ref_fs_p = fs; return (0); }
int shfs_rev_diff(shfs_ino_t *file, shkey_t *rev_key, shbuf_t *buff) { shbuf_t *work_buff; shbuf_t *head_buff; shfs_ino_t *new_rev; shfs_ino_t *delta; shfs_ino_t *rev; shfs_t *fs; int err; if (!file || shfs_type(file) != SHINODE_FILE) return (SHERR_INVAL); if (!buff) return (SHERR_INVAL); if (!rev_key) { /* obtain current committed revision. */ rev = shfs_rev_base(file); } else { rev = shfs_rev_get(file, rev_key); } if (!rev) return (SHERR_NOENT); /* obtain work-data for BASE branch revision. */ head_buff = shbuf_init(); err = shfs_rev_ref_read(file, "tag", "BASE", head_buff); if (err) { shbuf_free(&head_buff); return (err); } work_buff = shbuf_init(); err = shfs_read(file, work_buff); if (err) { shbuf_free(&head_buff); shbuf_free(&work_buff); return (err); } if (shbuf_size(work_buff) == shbuf_size(head_buff) && 0 == memcmp(shbuf_data(work_buff), shbuf_data(head_buff), shbuf_size(work_buff))) { /* no difference to report */ err = 0; } else { /* print textual difference to <buff> */ err = shdiff(buff, shbuf_data(work_buff), shbuf_data(head_buff)); } shbuf_free(&work_buff); shbuf_free(&head_buff); return (err); }
/** * @param file The inode refeferencing another inode. * @param ref_file The inode being referenced. */ int shfs_ref_set(shfs_ino_t *file, shfs_ino_t *ref_file) { shfs_ino_t *parent; shbuf_t *buff; int err; int i; if (!file || !file->tree) return (SHERR_INVAL); if (shfs_type(file) != shfs_type(ref_file)) { if (shfs_type(ref_file) != SHINODE_DIRECTORY) return (SHERR_ISDIR); return (SHERR_NOTDIR); } buff = shbuf_init(); shbuf_cat(buff, &file->tree->peer, sizeof(shpeer_t)); parent = ref_file; for (i = 0; i < SHFS_MAX_REFERENCE_HIERARCHY; i++) { if (parent) { shbuf_cat(buff, &parent->blk.hdr.name, sizeof(shkey_t)); parent = shfs_inode_parent(parent); } } err = _shfs_ref_raw_write(file, buff); shbuf_free(&buff); if (err) return (err); err = shfs_inode_write_entity(file); if (err) return (err); return (0); }
int shfs_lock_of(shfs_ino_t *inode, int flags, size_t of, size_t len) { shstat st; int err; err = shfs_fstat(inode, &st); if (err) return (err); if (shfs_type(inode) == SHINODE_FILE_LOCK) return (SHERR_OPNOTSUPP); return (shfs_attr_set(inode, SHATTR_FLOCK)); }
int shfs_unlock(shfs_ino_t *inode) { shstat st; int err; err = shfs_fstat(inode, &st); if (err) return (err); if (shfs_type(inode) == SHINODE_FILE_LOCK) return (SHERR_OPNOTSUPP); return (shfs_attr_unset(inode, SHATTR_FLOCK)); }
int shfs_rev_delta(shfs_ino_t *file, shbuf_t *diff_buff) { shstat st; shbuf_t *work_buff; shbuf_t *head_buff; shbuf_t *ref_buff; shfs_t *fs; shkey_t *key; int err; if (shfs_type(file) != SHINODE_FILE) return (SHERR_INVAL); err = shfs_fstat(file, &st); if (err) return (err); work_buff = shbuf_init(); err = shfs_read(file, work_buff); if (err) { shbuf_free(&work_buff); return (err); } /* obtain BASE branch snapshot */ head_buff = shbuf_init(); err = shfs_rev_ref_read(file, "tag", "BASE", head_buff); if (err) goto done; if (shbuf_size(work_buff) == shbuf_size(head_buff) && 0 == memcmp(shbuf_data(work_buff), shbuf_data(head_buff), shbuf_size(work_buff))) { /* no difference */ err = SHERR_AGAIN; goto done; } err = shdelta(work_buff, head_buff, diff_buff); done: shbuf_free(&work_buff); shbuf_free(&head_buff); shbuf_free(&work_buff); return (err); }
static int _shfs_lock_verify_hier(shfs_ino_t *inode) { shfs_t *parent; int err; if (shfs_type(inode) == SHINODE_FILE_LOCK) return (SHERR_OPNOTSUPP); if ((shfs_attr(inode) & SHATTR_FLOCK)) { return (SHERR_ACCESS); } /* reference fs from parent for fresh inodes */ parent = shfs_inode_parent(inode); if (parent) { err = _shfs_lock_verify_hier(parent); if (err) return (err); } return (0); }
int shfs_truncate(shfs_ino_t *file, shsize_t len) { shfs_ino_t *bin; shfs_ino_t *aux; int err; if (!file) return (0); if (!IS_INODE_CONTAINER(shfs_type(file))) return (SHERR_INVAL); /* see shfs_inode_truncate() */ switch (shfs_format(file)) { case SHINODE_NULL: return (SHERR_NOENT); /* no data content */ case SHINODE_BINARY: bin = shfs_inode(file, NULL, SHINODE_BINARY); err = shfs_inode_truncate(bin, len); if (err) return (err); /* update file inode attributes */ file->blk.hdr.mtime = bin->blk.hdr.mtime; file->blk.hdr.size = bin->blk.hdr.size; file->blk.hdr.crc = bin->blk.hdr.crc; err = shfs_inode_write_entity(file); if (err) return (err); break; default: return (SHERR_OPNOTSUPP); } return (0); }
int shfs_rev_checkout(shfs_ino_t *file, shkey_t *key, shfs_ino_t **rev_p) { shfs_ino_t *repo; shfs_ino_t *rev; int err; if (!file || shfs_type(file) != SHINODE_FILE) return (SHERR_INVAL); repo = shfs_inode(file, NULL, SHINODE_REPOSITORY); rev = shfs_rev_get(repo, key); if (!rev) return (SHERR_NOENT); err = shfs_rev_base_set(file, rev); if (err) return (err); if (rev_p) *rev_p = rev; return (0); }
int share_file_copy(char **args, int arg_cnt, int pflags) { shfs_t *dest_fs; shfs_t *src_fs; shfs_ino_t *dest_file; shfs_ino_t *src_file; shbuf_t *buff; char fpath[PATH_MAX+1]; unsigned char *data; size_t data_len; size_t of; int total; int src_cnt; int w_len; int err; int i; if (arg_cnt < 2) return (SHERR_INVAL); arg_cnt--; dest_fs = shfs_uri_init(args[arg_cnt], O_CREAT, &dest_file); if (!dest_fs) return (SHERR_IO); total = 0; for (i = 1; i < arg_cnt; i++) { err = share_file_stat_recursive(dest_file, args[i], &total); if (err) break; } if (err) { shfs_free(&dest_fs); return (err); } if (total == 0) { /* no matches */ shfs_free(&dest_fs); return (SHERR_INVAL); } if (total > 1 && shfs_type(dest_file) != SHINODE_DIRECTORY) { /* cannot copy multiple files to a single file */ shfs_free(&dest_fs); return (SHERR_NOTDIR); } err = 0; for (i = 1; i < arg_cnt; i++) { err = share_file_copy_recursive(dest_file, args[i]); if (err) break; } if (err) { shfs_free(&dest_fs); return (err); } shfs_free(&dest_fs); return (0); }
int shfs_file_remove(shfs_ino_t *file) { shfs_ino_t *child; shbuf_t *buff; shfs_dirent_t *ents; size_t ent_max; int fmt; int err; int i; if (IS_INODE_CONTAINER(shfs_type(file))) { ents = NULL; ent_max = shfs_list(file, NULL, &ents); if (ent_max < 0) { return (ent_max); } if (ents) { for (i = 0; i < ent_max; i++) { if (IS_INODE_CONTAINER(ents[i].d_type)) { child = shfs_inode(file, ents[i].d_name, ents[i].d_type); err = shfs_file_remove(child); if (err) return (err); } else { child = shfs_inode(file, NULL, ents[i].d_type); shfs_inode_clear(child); } } free(ents); } else { /* version repository */ if (shfs_attr(file) & SHATTR_VER) { child = shfs_inode(file, NULL, SHINODE_REPOSITORY); err = shfs_file_remove(child); if (err) return (err); } /* specific format */ fmt = shfs_format(file); if (fmt == SHINODE_NULL && shfs_type(file) == SHINODE_BINARY) { fmt = SHINODE_AUX; } if (fmt != SHINODE_NULL) { child = shfs_inode(file, NULL, fmt); if (!IS_INODE_CONTAINER(shfs_type(child))) { err = shfs_inode_clear(child); } else { err = shfs_file_remove(child); } if (err) return (err); } } } if (shfs_type(file) != SHINODE_DIRECTORY) { #if 0 /* DEBUG: perform inode_clear on 'fpos' index */ /* clear previous format */ err = shfs_format_set(file, SHINODE_NULL); if (err) return (err); #endif /* reset stats on file inode. */ file->blk.hdr.mtime = 0; file->blk.hdr.size = 0; // file->blk.hdr.type = SHINODE_NULL; file->blk.hdr.format = SHINODE_NULL; file->blk.hdr.attr = SHINODE_NULL; file->blk.hdr.crc = 0; err = shfs_inode_write_entity(file); if (err) { return (err); } } return (0); }
/** * Generates the working-copy for a particular revision. */ int shfs_rev_read(shfs_ino_t *i_rev, shbuf_t *buff) { shfs_ino_t *repo; shfs_ino_t *file; shfs_ino_t *rev; shbuf_t *delta_buff; shbuf_t *head_buff; shbuf_t *out_buff; int err; if (shfs_type(i_rev) != SHINODE_REVISION) { return (SHERR_INVAL); } repo = shfs_inode_parent(i_rev); if (!repo || shfs_type(repo) != SHINODE_REPOSITORY) return (SHERR_IO); file = shfs_inode_parent(repo); if (!file || shfs_type(file) != SHINODE_FILE) return (SHERR_IO); head_buff = shbuf_init(); err = shfs_rev_ref_read(file, "tag", "BASE", head_buff); if (err) return (err); err = SHERR_NOENT; /* ret'd when no matching revision found */ out_buff = shbuf_init(); delta_buff = shbuf_init(); /* search BASE chain for revision -- applying each revision's patch. */ rev = shfs_rev_tag_resolve(file, "BASE"); while (rev) { if (shkey_cmp(shfs_token(rev), shfs_token(i_rev))) { /* found revision in branch chain. */ shbuf_append(head_buff, buff); err = 0; break; } shbuf_clear(delta_buff); err = shfs_rev_delta_read(rev, delta_buff); if (err) break; /* DEBUG: TODO: merge together deltas to reduce performance over-head */ shbuf_clear(out_buff); err = shpatch(head_buff, delta_buff, out_buff); if (err) break; shbuf_clear(head_buff); shbuf_append(out_buff, head_buff); rev = shfs_rev_prev(rev); } shbuf_free(&head_buff); shbuf_free(&out_buff); shbuf_free(&delta_buff); return (err); }
int shfs_file_copy(shfs_ino_t *src_file, shfs_ino_t *dest_file) { shfs_t *ref_fs; shfs_ino_t *ref; shstat st; shbuf_t *buff; int err; if (!src_file || !dest_file) return (SHERR_INVAL); /* ensure there is something to copy */ err = shfs_fstat(src_file, &st); if (err) { fprintf(stderr, "DEBUG: shfs_file_copy: %d = shfs_fstat(src_file)\n", err); return (err); } if (shfs_type(dest_file) == SHINODE_DIRECTORY) { #if 0 /* extract tar archive */ if (shfs_format(dest_file) == SHINODE_BINARY && 0 == strcmp(shfs_meta_get(dest_file, "content.mime"), "application/x-tar")) { buff = shbuf_init(); err = shfs_read(src_file, buff); if (err) { shbuf_free(&buff); return (err); } err = shfs_unarch(buff, dest_file); shbuf_free(&buff); return (0); } #endif if (!(shfs_attr(src_file) & SHATTR_ARCH)) { if (IS_INODE_CONTAINER(shfs_type(src_file))) { dest_file = shfs_inode(dest_file, shfs_filename(src_file), shfs_type(src_file)); } else { dest_file = shfs_inode(dest_file, NULL, shfs_type(src_file)); } } } ref = NULL; ref_fs = NULL; if (shfs_format(dest_file) == SHINODE_REFERENCE) { /* apply operation to end-point inode. */ err = shfs_ref_get(dest_file, &ref_fs, &ref); if (err) { fprintf(stderr, "DEBUG: shfs_file_copy: %d = shfs_ref_get(dest_file)\n", err); return (err); } dest_file = ref; } if (shfs_format(dest_file) != SHINODE_EXTERNAL) { /* direct copy data content without conversion when applicable. */ switch (shfs_format(src_file)) { #if 0 case SHINODE_COMPRESS: err = shfs_zlib_copy(src_file, dest_file); if (err) return (err); return (0); #endif } } /* default case */ buff = shbuf_init(); err = shfs_read(src_file, buff); if (err) { fprintf(stderr, "DEBUG: shfs_file_copy: %d = shfs_read()\n", err); goto done; } err = shfs_write(dest_file, buff); shbuf_free(&buff); if (err) { fprintf(stderr, "DEBUG: shfs_file_copy: %d = shfs_write()\n", err); goto done; } /* success */ err = 0; done: shbuf_free(&buff); if (ref_fs) shfs_free(&ref_fs); return (err); }
int shfs_attr_set(shfs_ino_t *file, int attr) { shfs_attr_t cur_flag; shmime_t *mime; int err_code; if (!file || !attr) return (SHERR_INVAL); cur_flag = shfs_attr(file); if (cur_flag & attr) return (0); /* already set */ err_code = SHERR_OPNOTSUPP; switch (attr) { case SHATTR_ARCH: if (shfs_type(file) == SHINODE_DIRECTORY) { err_code = 0; } break; case SHATTR_COMP: if (shfs_type(file) == SHINODE_DIRECTORY) { /* files inherit */ err_code = 0; break; } err_code = shfs_format_set(file, SHINODE_COMPRESS); break; case SHATTR_SYNC: err_code = 0; //err_code = shfs_file_notify(file); break; case SHATTR_TEMP: err_code = 0; break; case SHATTR_VER: err_code = shfs_rev_init(file); break; case SHATTR_READ: case SHATTR_WRITE: case SHATTR_EXE: err_code = 0; break; case SHATTR_DB: if (shfs_type(file) != SHINODE_FILE || shfs_format(file) != SHINODE_NULL) { /* not a file or already contains content */ err_code = SHERR_INVAL; break; } err_code = 0; #if 0 err_code = shfs_format_set(file, SHINODE_DATABASE); #endif #if 0 if (shfs_size(file) == 0) { /* new database. */ err_code = 0; } mime = shmime_file(file); if (!mime || 0 == strcmp(mime->mime_name, SHMIME_APP_SQLITE)) { err_code = SHERR_INVAL; break; } /* DEBUG: move to copy file area */ #endif break; } if (!err_code) { file->blk.hdr.attr |= attr; err_code = shfs_inode_write_entity(file); } if (!err_code && ((file->blk.hdr.attr & SHATTR_SYNC) || (cur_flag & cur_flag))) { /* notify share daemon of altered attribute state for synchronized inode. */ shfs_file_notify(file); } return (err_code); }
int share_file_copy_recursive(SHFL *dest_file, char *fname) { shfs_dirent_t *ents; shfs_t *fs; SHFL **files; SHFL *dir; struct stat st; char spec_prefix[SHFS_PATH_MAX]; char spec_dir[SHFS_PATH_MAX]; char spec_fname[SHFS_PATH_MAX]; char path[SHFS_PATH_MAX]; char work_path[SHFS_PATH_MAX]; char buf[4096]; char *list_fname; char *ptr; int ent_nr; int err; int i; memset(spec_prefix, 0, sizeof(spec_prefix)); ptr = strstr(fname, ":/"); if (ptr) { ptr += 2; strncpy(spec_prefix, fname, MIN(sizeof(spec_prefix)-1, (ptr-fname))); fname += strlen(spec_prefix); } if (!strchr(fname, '/') || 0 == strncmp(fname, "./", 2)) { if (0 == strncmp(fname, "./", 2)) fname += 2; strcpy(spec_prefix, "file:/"); getcwd(buf, sizeof(buf)-1); strcat(buf, "/"); strcat(buf, fname); ptr = strrchr(buf, '/'); strncpy(spec_dir, buf + 1, strlen(buf) - strlen(ptr)); sprintf(spec_fname, "%s%s", spec_dir, ptr+1); list_fname = basename(spec_fname); } else { memset(spec_fname, 0, sizeof(spec_fname)); strncpy(spec_fname, fname, sizeof(spec_fname)-1); list_fname = basename(spec_fname); memset(spec_dir, 0, sizeof(spec_dir)); strncpy(spec_dir, fname, MIN(strlen(fname) - strlen(list_fname), sizeof(spec_dir)-1)); } sprintf(path, "%s%s", spec_prefix, spec_dir); fprintf(stderr, "DEBUG: file_recursive: shfs_uri_init(%s)\n", path); fs = shfs_uri_init(path, 0, &dir); if (!*list_fname) { /* directory reference. */ ent_nr = 1; files = (SHFL **)calloc(ent_nr+1, sizeof(SHFL *)); if (!files) return (SHERR_NOMEM); files[0] = dir; } else { /* search files in directory */ err = 0; ent_nr = shfs_list(dir, list_fname, &ents); if (ent_nr <= 0) return (ent_nr); err = SHERR_NOENT; files = (SHFL **)calloc(ent_nr+1, sizeof(SHFL *)); if (!files) return (SHERR_NOMEM); for (i = 0; i < ent_nr; i++) { ptr = strstr(spec_dir, ":/"); if (ptr) { sprintf(path, "%s%s", ptr+2, ents[i].d_name); } else { sprintf(path, "%s%s", spec_dir, ents[i].d_name); } err = shfs_stat(fs, path, &st); if (err) break; files[i] = shfs_file_find(fs, path); } shfs_list_free(&ents); if (err) { free(files); return (err); } } #if 0 /* handle recursive hierarchy */ if ((run_flags & PFLAG_RECURSIVE)) { for (i = 0; i < ent_nr; i++) { if (shfs_type(files[i]) != SHINODE_DIRECTORY) continue; /* .. */ } } #endif for (i = 0; i < ent_nr; i++) { /* perform file copy */ err = shfs_file_copy(files[i], dest_file); if (err) { fprintf(sharetool_fout, "%s: error copying \"%s\" to \"%s\": %s [sherr %d].\n", process_path, shfs_filename(files[i]), shfs_filename(dest_file), sherrstr(err), err); return (err); } if (!(run_flags & PFLAG_QUIET) && (run_flags & PFLAG_VERBOSE)) { fprintf(sharetool_fout, "%s: %s \"%s\" copied to %s \"%s\".\n", process_path, shfs_type_str(shfs_type(files[i])), shfs_filename(files[i]), shfs_type_str(shfs_type(dest_file)), shfs_filename(dest_file)); } } free(files); shfs_free(&fs); return (0); }