int ct_extract_open_next(struct ct_extract_head *extract_head, struct ctfile_parse_state *ctx) { struct ct_extract_stack *next; int ret, s_errno; if (!TAILQ_EMPTY(extract_head)) { next = TAILQ_FIRST(extract_head); CNDBG(CT_LOG_CTFILE, "should start restoring [%s]", next->filename); /* Basedir not needed here because we are done with prevlvl */ if ((ret = ctfile_parse_init(ctx, next->filename, NULL)) != 0) { s_errno = errno; /* chain is broken, clean it up */ ct_extract_cleanup_queue(extract_head); errno = s_errno; return (ret); } TAILQ_REMOVE(extract_head, next, next); if (next->filename) e_free(&next->filename); if (next) e_free(&next); } else { CABORTX("open next with no next archive"); } return (0); }
int ct_extract_setup(struct ct_extract_head *extract_head, struct ctfile_parse_state *ctx, const char *file, const char *ctfile_basedir, int *is_allfiles) { struct ct_extract_stack *nfile; char *prevlvl; int ret; if ((ret = ctfile_parse_init(ctx, file, ctfile_basedir)) != 0) return (ret); *is_allfiles = (ctx->xs_gh.cmg_flags & CT_MD_MLB_ALLFILES); if (ctx->xs_gh.cmg_prevlvl_filename) { nfile = e_malloc(sizeof(*nfile)); nfile->filename = e_strdup(file); TAILQ_INSERT_HEAD(extract_head, nfile, next); prevlvl = e_strdup(ctx->xs_gh.cmg_prevlvl_filename); ctfile_parse_close(ctx); if ((ret = ct_extract_setup_queue(extract_head, ctx, prevlvl, ctfile_basedir, *is_allfiles)) != 0) { int s_errno = errno; /* unwind */ e_free(&prevlvl); ct_extract_cleanup_queue(extract_head); errno = s_errno; return (ret); } e_free(&prevlvl); if (*is_allfiles) { ctfile_parse_close(ctx); /* reopen first file */ ret = ct_extract_open_next(extract_head, ctx); } } return (ret); }
static int ct_extract_setup_queue(struct ct_extract_head *extract_head, struct ctfile_parse_state *ctx, const char *file, const char *ctfile_basedir, int is_allfiles) { char *prevlvl; struct ct_extract_stack *nfile; int ret; if ((ret = ctfile_parse_init(ctx, file, ctfile_basedir)) != 0) return (ret); if (ctx->xs_gh.cmg_prevlvl_filename) { /* need to nest another level deep.*/ nfile = e_malloc(sizeof(*nfile)); nfile->filename = e_strdup(file); if (is_allfiles) TAILQ_INSERT_TAIL(extract_head, nfile, next); else TAILQ_INSERT_HEAD(extract_head, nfile, next); prevlvl = e_strdup(ctx->xs_gh.cmg_prevlvl_filename); ctfile_parse_close(ctx); ct_extract_setup_queue(extract_head, ctx, prevlvl, ctfile_basedir, is_allfiles); e_free(&prevlvl); } else if (is_allfiles) { /* * Allfiles we work backwards down the chain, without it * we work at the end and go backwards. Since this is the last * entry we only need it for allfiles mode. */ nfile = e_malloc(sizeof(*nfile)); nfile->filename = e_strdup(file); TAILQ_INSERT_TAIL(extract_head, nfile, next); } return (0); }
int ct_list(const char *file, char **flist, char **excludelist, int match_mode, const char *ctfile_basedir, int strip_slash, int verbose) { struct ct_extract_state *ces; struct ctfile_parse_state xs_ctx; struct fnode fnodestore; uint64_t reduction; struct fnode *fnode = &fnodestore; struct ct_match *match, *ex_match = NULL; char *ct_next_filename; char *sign; int state; int doprint = 0; int ret; int s_errno = 0, ct_errno = 0; char shat[SHA_DIGEST_STRING_LENGTH]; char cshat[SHA_DIGEST_STRING_LENGTH]; char iv[CT_IV_LEN*2+1]; if ((ret = ct_file_extract_init(&ces, NULL, 1, 1, 0, NULL, NULL)) != 0) CFATALX("failed to initialise extract state: %s", ct_strerror(ret)); if ((ret = ct_match_compile(&match, match_mode, flist)) != 0) CFATALX("failed to compile match pattern: %s", ct_strerror(ret)); if (excludelist != NULL && (ret = ct_match_compile(&ex_match, match_mode, excludelist)) != 0) CFATALX("failed to compile exclude pattern: %s", ct_strerror(ret)); verbose++; /* by default print something. */ ct_next_filename = NULL; next_file: ret = ctfile_parse_init(&xs_ctx, file, ctfile_basedir); if (ret) CFATALX("failed to open %s: %s", file, ct_strerror(ret)); ct_print_ctfile_info(&verbose, file, &xs_ctx.xs_gh); if (ct_next_filename) e_free(&ct_next_filename); if (xs_ctx.xs_gh.cmg_prevlvl_filename) { CNDBG(CT_LOG_CTFILE, "previous backup file %s\n", xs_ctx.xs_gh.cmg_prevlvl_filename); ct_next_filename = e_strdup(xs_ctx.xs_gh.cmg_prevlvl_filename); } bzero(&fnodestore, sizeof(fnodestore)); do { ret = ctfile_parse(&xs_ctx); switch (ret) { case XS_RET_FILE: ct_populate_fnode(ces, &xs_ctx, fnode, &state, xs_ctx.xs_gh.cmg_flags & CT_MD_MLB_ALLFILES, strip_slash); doprint = !ct_match(match, fnode->fn_fullname); if (doprint && ex_match != NULL && !ct_match(ex_match, fnode->fn_fullname)) doprint = 0; if (doprint) { ct_pr_fmt_file(&verbose, fnode); if (!C_ISREG(xs_ctx.xs_hdr.cmh_type) || verbose > 2) printf("\n"); } if (fnode->fn_hlname) e_free(&fnode->fn_hlname); if (fnode->fn_fullname) e_free(&fnode->fn_fullname); break; case XS_RET_FILE_END: sign = " "; if (xs_ctx.xs_trl.cmt_comp_size == 0) reduction = 100; else { uint64_t orig, comp; orig = xs_ctx.xs_trl.cmt_orig_size; comp = xs_ctx.xs_trl.cmt_comp_size; if (comp <= orig) { reduction = 100 * (orig - comp) / orig; } else { reduction = 100 * (comp - orig) / orig; if (reduction != 0) sign = "-"; } } if (doprint && verbose > 1) printf(" sz: %" PRIu64 " shas: %" PRIu64 " reduction: %s%" PRIu64 "%%\n", xs_ctx.xs_trl.cmt_orig_size, xs_ctx.xs_hdr.cmh_nr_shas, sign, reduction); else if (doprint) printf("\n"); break; case XS_RET_SHA: if (!(doprint && verbose > 2)) { if (ctfile_parse_seek(&xs_ctx)) { CFATALX("seek failed"); } } else { int i; ct_sha1_encode(xs_ctx.xs_sha, shat); switch (xs_ctx.xs_gh.cmg_flags & CT_MD_CRYPTO) { case 0: printf(" sha %s\n", shat); break; case CT_MD_CRYPTO: ct_sha1_encode(xs_ctx.xs_csha, cshat); for (i = 0; i < CT_IV_LEN; i++) snprintf(&iv[i * 2], 3, "%02x", xs_ctx.xs_iv[i]); printf(" sha %s csha %s iv %s\n", shat, cshat, iv); } } break; case XS_RET_EOF: break; case XS_RET_FAIL: s_errno = errno; ct_errno = xs_ctx.xs_errno; ; } } while (ret != XS_RET_EOF && ret != XS_RET_FAIL); ctfile_parse_close(&xs_ctx); if (ret != XS_RET_EOF) { errno = s_errno; CWARNX("corrupt ctfile: %s", ct_strerror(ct_errno)); } else { if (ct_next_filename) { file = ct_next_filename; goto next_file; } } ct_match_unwind(match); ct_file_extract_cleanup(ces); return (0); }