const shseed_t *shpam_shadow_pass(shfs_ino_t *file, uint64_t uid) { static shseed_t ret_seed; shbuf_t *buff; shseed_t *seeds; int total; int idx; int err; memset(&ret_seed, 0, sizeof(ret_seed)); buff = shbuf_init(); err = shfs_read(file, buff); if (err) { shbuf_free(&buff); return (NULL); } seeds = (shseed_t *)shbuf_data(buff); total = shbuf_size(buff) / sizeof(shseed_t); for (idx = 0; idx < total; idx++) { if (seeds[idx].seed_uid == uid) { memcpy(&ret_seed, &seeds[idx], sizeof(shseed_t)); break; } } shbuf_free(&buff); if (idx != total) { return (&ret_seed); } return (NULL); }
int shfs_file_pipe(shfs_ino_t *file, int fd) { shbuf_t *buff; ssize_t b_of; int b_len; int err; if (file == NULL) return (SHERR_NOENT); buff = shbuf_init(); err = shfs_read(file, buff); if (err) { shbuf_free(&buff); return (err); } for (b_of = 0; b_of < buff->data_of; b_of++) { b_len = write(fd, buff->data + b_of, buff->data_of - b_of); if (b_len < 0) { shbuf_free(&buff); return (-errno); } b_of += b_len; } shbuf_free(&buff); return (0); }
int shfs_read_mem(char *path, char **data_p, size_t *data_len_p) { shbuf_t *buff; size_t data_len; int err; buff = shbuf_init(); err = shfs_mem_read(path, buff); if (err) { shbuf_free(&buff); return (err); } data_len = shbuf_size(buff); if (data_len_p) { *data_len_p = data_len; } if (data_p) { *data_p = shbuf_unmap(buff); } else { shbuf_free(&buff); } return (0); }
int shpam_shadow_pass_remove(shfs_ino_t *file, uint64_t rem_uid) { shbuf_t *rbuff; shbuf_t *buff; shseed_t *seeds; int total; int idx; int err; rbuff = shbuf_init(); shfs_read(file, rbuff); buff = shbuf_init(); seeds = (shseed_t *)shbuf_data(rbuff); total = shbuf_size(rbuff) / sizeof(shseed_t); for (idx = 0; idx < total; idx++) { if (seeds[idx].seed_uid == rem_uid) continue; shbuf_cat(buff, &seeds[idx], sizeof(shseed_t)); } shbuf_free(&rbuff); err = shfs_write(file, buff); shbuf_free(&buff); if (err) return (err); 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); }
int share_file_cat(char *path, int pflags) { shstat st; shfs_t *tree; shfs_ino_t *file; shbuf_t *buff; char fpath[PATH_MAX+1]; unsigned char *data; size_t data_len; size_t of; int w_len; int err; tree = shfs_uri_init(path, 0, &file); if (!tree) return (SHERR_NOENT); err = shfs_fstat(file, &st); if (err) { shfs_free(&tree); return (err); } buff = shbuf_init(); err = shfs_read(file, buff); if (err) { shbuf_free(&buff); shfs_free(&tree); return (err); } of = 0; while (of < shbuf_size(buff)) { data_len = MIN((shbuf_size(buff) - of), 65536); data = shbuf_data(buff) + of; w_len = fwrite(data, sizeof(char), data_len, sharetool_fout); if (w_len < 0) { shbuf_free(&buff); shfs_free(&tree); return (-errno); } of += w_len; } shbuf_free(&buff); shfs_free(&tree); return (0); }
int shpam_shadow_pass_append(shfs_ino_t *file, shseed_t *seed) { shbuf_t *buff; shseed_t *seeds; int total; int idx; int err; buff = shbuf_init(); shfs_read(file, buff); seeds = (shseed_t *)shbuf_data(buff); total = shbuf_size(buff) / sizeof(shseed_t); for (idx = 0; idx < total; idx++) { if (seeds[idx].seed_uid == seed->seed_uid) { memcpy(&seeds[idx], seed, sizeof(shseed_t)); break; } } if (idx == total) { shbuf_cat(buff, seed, sizeof(shseed_t)); } err = shfs_write(file, buff); shbuf_free(&buff); if (err) return (err); return (0); }
void sched_tx_payload(shkey_t *dest_key, void *data, size_t data_len, void *payload, size_t payload_len) { tx_t *tx = (tx_t *)data; tx_t sig_tx; tx_net_t net; shsig_t sig; shsig_t new_sig; shbuf_t *buff; shpeer_t *self_peer; if (!data) return; if (data_len < sizeof(tx_t)) return; prep_net_tx(tx, &net, dest_key, data_len + payload_len); buff = shbuf_init(); shbuf_cat(buff, &net, sizeof(tx_net_t)); shbuf_cat(buff, data, data_len); if (payload && payload_len) shbuf_cat(buff, payload, payload_len); tx_wrap(NULL, shbuf_data(buff) + sizeof(tx_net_t)); broadcast_raw(shbuf_data(buff), shbuf_size(buff)); shbuf_free(&buff); fprintf(stderr, "DEBUG: SEND: sched_tx_payload: [OP %d] hash(%s) peer(%s) stamp(%llu) nonce(%d) method(%d) OP(%d)\n", (int)tx->tx_op, tx->hash, shkey_print(&tx->tx_peer), (unsigned long long)tx->tx_stamp, (int)tx->nonce, TXHASH_SCRYPT, (int)tx->tx_op); }
int shproc_stop(shproc_t *proc) { int err; if (child_proc) return (SHERR_INVAL); if (proc->proc_pid == 0) return (SHERR_INVAL); if (proc->proc_state == SHPROC_NONE) return (0); /* all done */ err = kill(proc->proc_pid, SIGQUIT); if (err) return (err); shproc_state_set(proc, SHPROC_NONE); shbuf_free(&proc->proc_buff); close(proc->proc_fd); close(proc->dgram_fd); proc->proc_fd = proc->proc_pid = 0; proc->dgram_fd = 0; return (0); }
int install_sexe_userdata(sexe_t *S, char *tag) { SHFL *fl; shjson_t *udata; shfs_t *fs; shbuf_t *buff; shkey_t *k; char path[PATH_MAX+1]; int is_new; k = shkey_str(tag); sprintf(path, "/sys/data/sexe/%s", shkey_hex(k)); memcpy(&S->pname, k, sizeof(S->pname)); shkey_free(&k); buff = shbuf_init(); fs = shfs_init(NULL); fl = shfs_file_find(fs, path); is_new = shfs_read(fl, buff); udata = shjson_init(shbuf_size(buff) ? (char *)shbuf_data(buff) : NULL); shbuf_free(&buff); if (is_new) shjson_num_add(udata, "birth", shtimef(shtime())); sexe_table_set(S, udata); lua_setglobal(S, "userdata"); shjson_free(&udata); shfs_free(&fs); return (0); }
int shfs_file_notify(shfs_ino_t *file) { shfs_t *tree = file->tree; shbuf_t *buff; uint32_t mode; int qid; int err; if (!file || !tree) return (0); /* done */ qid = _shfs_file_qid(); if (qid == -1) return (SHERR_IO); buff = shbuf_init(); mode = TX_FILE; shbuf_cat(buff, &mode, sizeof(mode)); shbuf_cat(buff, &tree->peer, sizeof(shpeer_t)); shbuf_catstr(buff, shfs_inode_path(file)); err = shmsg_write(qid, buff, NULL); shbuf_free(&buff); 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_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); }
int shfs_rev_revert(shfs_ino_t *file) { shbuf_t *buff; int err; buff = shbuf_init(); err = shfs_rev_ref_read(file, "tag", "BASE", buff); if (err) { shbuf_free(&buff); return (err); } err = shfs_write(file, buff); shbuf_free(&buff); if (err) return (err); return (0); }
int shfs_file_read(shfs_ino_t *file, unsigned char *data, size_t data_len) { shbuf_t *buff; ssize_t r_len; int err; buff = shbuf_init(); err = shfs_read(file, buff); if (err) { shbuf_free(&buff); return (err); } r_len = MIN(shbuf_size(buff), data_len); if (shbuf_size(buff) != 0) memcpy(data, shbuf_data(buff), r_len); shbuf_free(&buff); return ((int)r_len); }
int shpam_pshadow_load(shfs_ino_t *file, uint64_t uid, shseed_t *ret_seed) { shbuf_t *buff; shseed_t *seeds; int total; int idx; int err; if (ret_seed) memset(ret_seed, 0, sizeof(shseed_t)); buff = shbuf_init(); err = shfs_read(file, buff); if (err) { shbuf_free(&buff); return (err); } seeds = (shseed_t *)shbuf_data(buff); total = shbuf_size(buff) / sizeof(shseed_t); if (!total) { shbuf_free(&buff); return (SHERR_NOENT); /* done */ } for (idx = 0; idx < total; idx++) { if (seeds[idx].seed_uid == uid) break; } if (idx == total) { shbuf_free(&buff); return (SHERR_NOENT); } if (ret_seed) memcpy(ret_seed, &seeds[idx], sizeof(shseed_t)); shbuf_free(&buff); return (0); }
static void shproc_worker_signal(int sig_num) { shbuf_free(&child_proc->proc_buff); close(child_proc->proc_fd); child_proc = NULL; /* user-supplied signal handler for spawned worker process */ if (_shproc_signal_handler) (*_shproc_signal_handler)(sig_num); exit(0); }
int shproc_child_poll(shproc_t *proc) { struct shproc_req_t req; struct timeval to; shbuf_t *sp_buf; fd_set in_set; int r_len; int err; int fd; err = shproc_read(proc); if (err == 1) return (0); /* nothing to do */ if (err) return (err); memset(&req, 0, sizeof(req)); /* spawned worker - data receieved as request */ sp_buf = shbuf_clone(proc->proc_buff); memset(&req, 0, sizeof(req)); req.state = SHPROC_RUN; shbuf_clear(proc->proc_buff); err = shproc_write(proc, &req); fd = 0; if (proc->user_fd) { fd = shproc_read_fd(proc); } err = 0; if (proc->proc_req) { err = (*proc->proc_req)(fd, sp_buf); /* user-result data */ shbuf_append(sp_buf, proc->proc_buff); } if (fd != 0) close(fd); shbuf_free(&sp_buf); memset(&req, 0, sizeof(req)); req.state = SHPROC_IDLE; req.error = err; err = shproc_write(proc, &req); proc->proc_idx++; shproc_state_set(proc, SHPROC_IDLE); shbuf_clear(proc->proc_buff); return (0); }
/** * Load supplementary credential data from a file. */ int shfs_cred_load(shfs_ino_t *file, shkey_t *key, unsigned char *data, size_t max_len) { shfs_ino_t *cred; shbuf_t *buff; char key_buf[MAX_SHARE_HASH_LENGTH]; int err; if (!(file->blk.hdr.attr & SHATTR_CRED)) return (SHERR_NOENT); memset(key_buf, 0, sizeof(key_buf)); sprintf(key_buf, "%s", shkey_hex(key)); cred = shfs_inode(file, key_buf, SHINODE_ACCESS); if (!cred) return (SHERR_IO); if (cred->blk.hdr.format != SHINODE_ACCESS) return (SHERR_NOENT); buff = shbuf_init(); err = shfs_aux_read(cred, buff); if (err) { shbuf_free(&buff); return (err); } if (shbuf_size(buff) == 0) { shbuf_free(&buff); return (SHERR_IO); } /* copy buffer */ memcpy(data, shbuf_data(buff), MIN(shbuf_size(buff), max_len)); shbuf_free(&buff); return (0); }
int update_sexe_userdata(sexe_t *S) { SHFL *fl; shjson_t *udata; shfs_t *fs; shbuf_t *buff; shkey_t *k; char path[PATH_MAX+1]; char *str; int err; k = &S->pname; if (shkey_cmp(k, ashkey_blank())) { fprintf(stderr, "DEBUG: update_sexe_userdata: no app key\n"); return (0); /* blank */ } sprintf(path, "/sys/data/sexe/%s", shkey_hex(k)); lua_getglobal(S, "userdata"); udata = sexe_table_get(S); if (!udata) { fprintf(stderr, "DEBUG: update_sexe_userdata: no global 'userdata' variable.\n"); return (SHERR_INVAL); } str = shjson_print(udata); if (!str) { fprintf(stderr, "DEBUG: update_sexe_userdata: error encoding JSON.\n"); return (SHERR_INVAL); } shjson_free(&udata); buff = shbuf_init(); shbuf_catstr(buff, str); free(str); fs = shfs_init(NULL); fl = shfs_file_find(fs, path); err = shfs_write(fl, buff); shbuf_free(&buff); shfs_free(&fs); return (err); }
void *pstore_read(int tx_op, char *name) { SHFL *fl; shbuf_t *buff; char path[PATH_MAX+1]; char prefix[256]; unsigned char *data; size_t data_len; int err; pstore_init(); memset(prefix, 0, sizeof(prefix)); switch (tx_op) { case TX_ACCOUNT: strcpy(prefix, "account"); break; case TX_IDENT: strcpy(prefix, "id"); break; case TX_SESSION: strcpy(prefix, "session"); break; case TX_APP: strcpy(prefix, "app"); break; case TX_LEDGER: strcpy(prefix, "ledger"); break; default: strcpy(prefix, "default"); break; } buff = shbuf_init(); sprintf(path, "/sys/net/tx/%s/%s", prefix, name); fl = shfs_file_find(_pstore_fs, path); err = shfs_read(fl, buff); if (err) { shbuf_free(&buff); return (NULL); } return (shbuf_unmap(buff)); }
int pstore_write(int tx_op, char *name, unsigned char *data, size_t data_len) { SHFL *fl; char prefix[256]; char path[PATH_MAX+1]; shbuf_t *buff; int err; pstore_init(); memset(prefix, 0, sizeof(prefix)); switch (tx_op) { case TX_ACCOUNT: strcpy(prefix, "account"); break; case TX_IDENT: strcpy(prefix, "id"); break; case TX_SESSION: strcpy(prefix, "session"); break; case TX_APP: strcpy(prefix, "app"); break; case TX_LEDGER: strcpy(prefix, "ledger"); break; default: strcpy(prefix, "default"); break; } sprintf(path, "/sys/net/tx/%s/%s", prefix, name); fl = shfs_file_find(_pstore_fs, path); buff = shbuf_init(); shbuf_cat(buff, data, data_len); err = shfs_write(fl, buff); shbuf_free(&buff); if (err) return (err); return (0); }
/** * @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 shpam_pshadow_store(shfs_ino_t *file, shseed_t *seed) { shbuf_t *buff; shseed_t *seeds; int total; int idx; int err; #if 0 /* ensure record exists. */ err = shpam_pshadow_load(file, seed->seed_uid, NULL); if (err) return (err); #endif buff = shbuf_init(); shfs_read(file, buff); seeds = (shseed_t *)shbuf_data(buff); total = shbuf_size(buff) / sizeof(shseed_t); for (idx = 0; idx < total; idx++) { if (seeds[idx].seed_uid == seed->seed_uid) { memcpy(&seeds[idx], seed, sizeof(shseed_t)); break; } } if (idx == total) { shbuf_cat(buff, seed, sizeof(shseed_t)); } err = shfs_write(file, buff); shbuf_free(&buff); if (err) return (err); return (0); }
int confirm_tx_key(txop_t *op, tx_t *tx) { shkey_t *c_key = &tx->tx_key; shkey_t *key; shbuf_t *buff; tx_t *k_tx; size_t len; int confirm; if (!op || !tx) return (SHERR_INVAL); if (op->op_size == 0) return (0); /* allocate working copy */ len = MAX(sizeof(tx_t), op->op_keylen ? op->op_keylen : op->op_size); buff = shbuf_init(); shbuf_cat(buff, (char *)tx, len); /* blank out tx key */ k_tx = (tx_t *)shbuf_data(buff); memset(&k_tx->tx_key, '\000', sizeof(k_tx->tx_key)); /* verify generated tx key matches. */ key = shkey_bin(shbuf_data(buff), shbuf_size(buff)); confirm = shkey_cmp(c_key, key); shkey_free(&key); shbuf_free(&buff); if (!confirm) { return (SHERR_INVAL); } return (0); }
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); }
/** * 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_rev_commit(shfs_ino_t *file, shfs_ino_t **rev_p) { shstat st; shbuf_t *diff_buff; shbuf_t *work_buff; shbuf_t *head_buff; shfs_ino_t *base; shfs_ino_t *repo; /* SHINODE_REPOSITORY */ shfs_ino_t *new_rev; /* SHINODE_REVISION */ shfs_ino_t *delta; /* SHINODE_DELTA */ shkey_t *rev_key; shfs_t *fs; int err; if (rev_p) *rev_p = NULL; head_buff = work_buff = diff_buff = NULL; err = shfs_fstat(file, &st); if (err) return (err); work_buff = shbuf_init(); err = shfs_read(file, work_buff); if (err) goto done; base = shfs_rev_base(file); if (base) { /* obtain delta of current file data content against BASE revision's data content. */ 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; } diff_buff = shbuf_init(); err = shdelta(work_buff, head_buff, diff_buff); shbuf_free(&head_buff); if (err) return (err); rev_key = shfs_token(base); } else { /* initial revision */ rev_key = ashkey_uniq(); } repo = shfs_inode(file, NULL, SHINODE_REPOSITORY); if (!repo) { err = SHERR_IO; goto done; } /* create a new revision using previous revision's inode name */ new_rev = shfs_inode(repo, (char *)shkey_hex(rev_key), SHINODE_REVISION); if (!new_rev) { err = SHERR_IO; goto done; } /* define revision's meta information. */ shfs_meta_set(new_rev, SHMETA_USER_NAME, (char *)get_libshare_account_name()); /* save delta to new revision */ err = shfs_rev_delta_write(new_rev, diff_buff); shbuf_free(&diff_buff); if (err) goto done; /* save new revision as BASE branch head */ err = shfs_rev_base_set(file, new_rev); if (err) goto done; /* save work-data to BASE tag. */ err = shfs_rev_ref_write(file, "tag", "BASE", work_buff); shbuf_free(&work_buff); if (err) goto done; if (base) { /* tag previous revision's key token onto revision inode. */ shfs_rev_tag(new_rev, "PREV", base); } if (rev_p) *rev_p = new_rev; done: shbuf_free(&work_buff); shbuf_free(&diff_buff); shbuf_free(&head_buff); return (err); }