static int extract(const char *filename, int arglen, char *args[]) { xar_t x; xar_iter_t i; xar_file_t f; int files_extracted = 0; x = xar_open(filename, READ); if( !x ) { fprintf(stderr, "Error opening xar archive: %s\n", filename); exit(1); } xar_register_errhandler(x, err_callback, NULL); if( Perms == SYMBOLIC ) { xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_SYMBOLIC); } if( Perms == NUMERIC ) { xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_NUMERIC); } if ( Rsize != NULL ) { xar_opt_set(x, XAR_OPT_RSIZE, Rsize); } i = xar_iter_new(); if( !i ) { fprintf(stderr, "Error creating xar iterator\n"); exit(1); } for(f = xar_file_first(x, i); f; f = xar_file_next(i)) { int matched = 0; int exclude_match = 1; struct lnode *i; char *path = xar_get_path(f); if( args[0] ) { int i; for(i = 0; args[i]; i++) { if( strcmp(path, args[i]) == 0 ) { matched = 1; break; } } } else { matched = 1; } for( i = Exclude; i; i=i->next ) { exclude_match = regexec(&i->reg, path, 0, NULL, 0); if( !exclude_match ) break; } if( !exclude_match ) { if( Verbose ) printf("Excluding %s\n", path); free(path); continue; } if( matched ) { files_extracted++; print_file(f); xar_extract(x, f); } free(path); } if( args[0] && (files_extracted == 0) ) { fprintf(stderr, "No files matched extraction criteria.\n"); Err = 3; } if( Subdoc ) extract_subdoc(x, NULL); xar_iter_free(i); if( xar_close(x) != 0 ) { fprintf(stderr, "Error extracting the archive\n"); if( !Err ) Err = 42; } return Err; }
/* replace_sign: rip out all current signatures and certs and insert a new pair Since libxar is currently not capable of doing this directly, we have to create a new xar archive, copy all the files and options from the current archive, and sign the new archive */ static void replace_sign(const char *filename) { xar_t old_xar, new_xar; xar_signature_t sig; char *new_xar_path = (char *)malloc(15); strncpy(new_xar_path, "/tmp/xar.XXXXX", 15); new_xar_path = mktemp(new_xar_path); char *systemcall; int err; // open both archives old_xar = xar_open(filename, READ); if ( old_xar == NULL ) { fprintf(stderr, "Could not open archive %s!\n", filename); exit(1); } new_xar = xar_open(new_xar_path, WRITE); if( !new_xar ) { fprintf(stderr, "Error creating new archive %s\n", new_xar_path); exit(1); } // install new signature and new certs in new_xar sig = xar_signature_new(new_xar, "RSA", SigSize, &signingCallback, NULL); if ( LeafCertPath ) insert_cert(sig, LeafCertPath); if ( IntermediateCertPath ) insert_cert(sig, IntermediateCertPath); // copy options char *opts[6] = {XAR_OPT_TOCCKSUM, XAR_OPT_COMPRESSION, XAR_OPT_COALESCE, XAR_OPT_LINKSAME, XAR_OPT_RSIZE, XAR_OPT_OWNERSHIP}; int i; const char *opt; for (i=0; i<6; i++) { opt = xar_opt_get(old_xar, opts[i]); if (opt) xar_opt_set(new_xar, opts[i], opt); } // skip copy subdocs for now since we don't use them yet // copy files xar_iter_t iter = xar_iter_new(); xar_file_t f = xar_file_first(old_xar, iter); // xar_file_next iterates the archive depth-first, i.e. all children are enumerated before the siblings. const char *name; char *f_dirname, *stack_top_dirname; stack s_new = stack_new(); stack s_old = stack_new(); xar_file_t last_copied = NULL, last_added; xar_iter_t loopIter = xar_iter_new(); xar_file_t current_xar_file; for (current_xar_file = xar_file_first(old_xar, loopIter); current_xar_file; current_xar_file = xar_file_next(loopIter)) { printf("old_xar -> %s (parent: %s)\n",xar_get_path(current_xar_file),XAR_FILE(current_xar_file)->parent?xar_get_path(XAR_FILE(current_xar_file)->parent):"(nil)"); } do { // parent is the parent in the new archive! // 3 cases: // 1. the file has no parent. Happens for every file at the top level of the archive. // 2. the file's parent is the last file we added. Happens while descending down a path // 3. the file's parent is one of the ancestors of the last file (and not NULL, that would be case 1) // that means we either go back up the tree and add a sibling of one of the ancestors, or we add a // sibling on the same level xar_prop_get(f, "name", &name); // filename, without any path info if (!XAR_FILE(f)->parent) { // case 1 printf("root: %s\n",xar_get_path(f)); last_added = xar_add_from_archive(new_xar, NULL, name, old_xar, f); last_copied = f; stack_push(s_new, (void *)last_added); stack_push(s_old, (void *)last_copied); } else if (f->parent == last_copied) { // case 2 printf("child: %s -> %s\n",xar_get_path(f->parent),xar_get_path(f)); last_added = xar_add_from_archive(new_xar, last_added, name, old_xar, f); last_copied = f; stack_push(s_new, (void *)last_added); stack_push(s_old, (void *)last_copied); } else { // case 3 printf("searching for parent: %s ?\n",xar_get_path(f)); while (XAR_FILE(f)->parent != XAR_FILE(s_old->top->data)->parent) { printf("popping: %s\n",xar_get_path(XAR_FILE(s_old->top->data))); stack_pop(s_new); stack_pop(s_old); } printf("found: %s -> %s\n",xar_get_path(XAR_FILE(s_new->top->data)),xar_get_path(f)); stack_pop(s_new); stack_pop(s_old); last_added = xar_add_from_archive(new_xar, (xar_file_t)(s_new->top->data), name, old_xar, f); last_copied = f; stack_push(s_new, (void *)last_added); stack_push(s_old, (void *)last_copied); } } while (f = xar_file_next(iter)); loopIter = xar_iter_new(); for (current_xar_file = xar_file_first(new_xar, loopIter); current_xar_file; current_xar_file = xar_file_next(loopIter)) { char * current_path = xar_get_path(current_xar_file); printf("new_xar -> %s\n",current_path); } xar_iter_free(iter); stack_free(s_new); stack_free(s_old); if( xar_close(new_xar) != 0 ) { fprintf(stderr, "Error creating the archive\n"); if( !Err ) Err = 42; } xar_close(old_xar); // write signature offset to file (have to re-open so xar_close can figure out the correct offset) new_xar = xar_open(new_xar_path, READ); if( !new_xar ) { fprintf(stderr, "Error re-opening new archive %s\n", new_xar_path); unlink(new_xar_path); exit(1); } if (extract_sig_offset(new_xar, SigOffsetDumpPath)) { xar_close(new_xar); unlink(new_xar_path); exit(1); } xar_close(new_xar); // delete old archive, move new in its place unlink(filename); asprintf(&systemcall, "cp \"%s\" \"%s\"", new_xar_path, filename); err = system(systemcall); if (err) { fprintf(stderr, "Could not copy new archive to final location (system() returned %i)\n", err); unlink(new_xar_path); exit(1); } // Delete the tmp archive unlink(new_xar_path); free(systemcall); }
static int archive(const char *filename, int arglen, char *args[]) { xar_t x; FTS *fts; FTSENT *ent; int flags; struct lnode *i; const char *default_compression; x = xar_open(filename, WRITE); if( !x ) { fprintf(stderr, "Error creating archive %s\n", filename); exit(1); } if ( SigSize ) { xar_signature_t sig = xar_signature_new(x, "RSA", SigSize, &signingCallback, NULL); if ( LeafCertPath ) insert_cert(sig, LeafCertPath); if ( IntermediateCertPath ) insert_cert(sig, IntermediateCertPath); } if( Toccksum ) xar_opt_set(x, XAR_OPT_TOCCKSUM, Toccksum); if( Compression ) xar_opt_set(x, XAR_OPT_COMPRESSION, Compression); if( Coalesce ) xar_opt_set(x, XAR_OPT_COALESCE, "true"); if( LinkSame ) xar_opt_set(x, XAR_OPT_LINKSAME, "true"); if ( Rsize != NULL ) xar_opt_set(x, XAR_OPT_RSIZE, Rsize); xar_register_errhandler(x, err_callback, NULL); if( Subdoc ) add_subdoc(x); if( Perms == SYMBOLIC ) { xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_SYMBOLIC); } if( Perms == NUMERIC ) { xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_NUMERIC); } default_compression = strdup(xar_opt_get(x, XAR_OPT_COMPRESSION)); if( !default_compression ) default_compression = strdup(XAR_OPT_VAL_GZIP); flags = FTS_PHYSICAL|FTS_NOSTAT|FTS_NOCHDIR; if( Local ) flags |= FTS_XDEV; fts = fts_open(args, flags, NULL); if( !fts ) { fprintf(stderr, "Error traversing file tree\n"); exit(1); } while( (ent = fts_read(fts)) ) { xar_file_t f; int exclude_match = 1; int nocompress_match = 1; if( ent->fts_info == FTS_DP ) continue; if( strcmp(ent->fts_path, "/") == 0 ) continue; if( strcmp(ent->fts_path, ".") == 0 ) continue; for( i = Exclude; i; i=i->next ) { exclude_match = regexec(&i->reg, ent->fts_path, 0, NULL, 0); if( !exclude_match ) break; } if( !exclude_match ) { if( Verbose ) printf("Excluding %s\n", ent->fts_path); continue; } for( i = NoCompress; i; i=i->next ) { nocompress_match = regexec(&i->reg, ent->fts_path, 0, NULL, 0); if( !nocompress_match ) { xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE); break; } } f = xar_add(x, ent->fts_path); if( !f ) { fprintf(stderr, "Error adding file %s\n", ent->fts_path); } else { print_file(f); } if( !nocompress_match ) xar_opt_set(x, XAR_OPT_COMPRESSION, default_compression); } fts_close(fts); if( xar_close(x) != 0 ) { fprintf(stderr, "Error creating the archive\n"); if( !Err ) Err = 42; } free((char *)default_compression); for( i = Exclude; i; ) { struct lnode *tmp; regfree(&i->reg); tmp = i; i = i->next; free(tmp); } for( i = NoCompress; i; ) { struct lnode *tmp; regfree(&i->reg); tmp = i; i = i->next; free(tmp); } if ( SigOffsetDumpPath ) { x = xar_open(filename, READ); if( !x ) { fprintf(stderr, "Error re-opening archive %s\n", filename); exit(1); } if (extract_sig_offset(x, SigOffsetDumpPath)) exit(1); } return Err; }
static int extract(const char *filename, int arglen, char *args[]) { xar_t x; xar_iter_t i; xar_file_t f; int files_extracted = 0; int argi; struct lnode *extract_files = NULL; struct lnode *extract_tail = NULL; struct lnode *lnodei = NULL; struct lnode *dirs = NULL; for(argi = 0; args[argi]; argi++) { struct lnode *tmp; int err; tmp = malloc(sizeof(struct lnode)); tmp->str = strdup(args[argi]); tmp->next = NULL; err = regcomp(&tmp->reg, tmp->str, REG_NOSUB); if( err ) { char errstr[1024]; regerror(err, &tmp->reg, errstr, sizeof(errstr)); printf("Error with regular expression %s: %s\n", tmp->str, errstr); exit(1); } if( extract_files == NULL ) { extract_files = tmp; extract_tail = tmp; } else { extract_tail->next = tmp; extract_tail = tmp; } /* Add a clause for recursive extraction */ tmp = malloc(sizeof(struct lnode)); asprintf(&tmp->str, "%s/.*", args[argi]); tmp->next = NULL; err = regcomp(&tmp->reg, tmp->str, REG_NOSUB); if( err ) { char errstr[1024]; regerror(err, &tmp->reg, errstr, sizeof(errstr)); printf("Error with regular expression %s: %s\n", tmp->str, errstr); exit(1); } if( extract_files == NULL ) { extract_files = tmp; extract_tail = tmp; } else { extract_tail->next = tmp; extract_tail = tmp; } } x = xar_open(filename, READ); if( !x ) { fprintf(stderr, "Error opening xar archive: %s\n", filename); exit(1); } if(Chdir) { if( chdir(Chdir) != 0 ) { fprintf(stderr, "Unable to chdir to %s\n", Chdir); exit(1); } } xar_register_errhandler(x, err_callback, NULL); if( Perms == SYMBOLIC ) { xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_SYMBOLIC); } if( Perms == NUMERIC ) { xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_NUMERIC); } if ( Rsize != NULL ) { xar_opt_set(x, XAR_OPT_RSIZE, Rsize); } if( SaveSuid ) { xar_opt_set(x, XAR_OPT_SAVESUID, XAR_OPT_VAL_TRUE); } i = xar_iter_new(); if( !i ) { fprintf(stderr, "Error creating xar iterator\n"); exit(1); } for(f = xar_file_first(x, i); f; f = xar_file_next(i)) { int matched = 0; int exclude_match = 1; struct lnode *i; char *path = xar_get_path(f); if( args[0] ) { for(i = extract_files; i != NULL; i = i->next) { int extract_match = 1; extract_match = regexec(&i->reg, path, 0, NULL, 0); if( !extract_match ) { matched = 1; break; } } } else { matched = 1; } for( i = Exclude; i; i=i->next ) { exclude_match = regexec(&i->reg, path, 0, NULL, 0); if( !exclude_match ) break; } if( !exclude_match ) { if( Verbose ) printf("Excluding %s\n", path); free(path); continue; } if (!xar_path_issane(path)) { if (Verbose) printf("Warning, not extracting file \"%s\" because it's path is invalid.\n", path); free(path); continue; } if( matched ) { struct stat sb; if( NoOverwrite && (lstat(path, &sb) == 0) ) { printf("%s already exists, not overwriting\n", path); } else { const char *prop = NULL; int deferred = 0; if( xar_prop_get(f, "type", &prop) == 0 ) { if( strcmp(prop, "directory") == 0 ) { struct lnode *tmpl = calloc(sizeof(struct lnode),1); tmpl->str = (char *)f; tmpl->next = dirs; dirs = tmpl; deferred = 1; } } if( ! deferred ) { files_extracted++; print_file(x, f); xar_extract(x, f); } } } free(path); } for(lnodei = dirs; lnodei; lnodei = lnodei->next) { files_extracted++; print_file(x,(xar_file_t)lnodei->str); xar_extract(x, (xar_file_t)lnodei->str); } if( args[0] && (files_extracted == 0) ) { fprintf(stderr, "No files matched extraction criteria.\n"); Err = 3; } if( Subdoc ) extract_subdoc(x, NULL); xar_iter_free(i); if( xar_close(x) != 0 ) { fprintf(stderr, "Error extracting the archive\n"); if( !Err ) Err = 42; } for(lnodei = extract_files; lnodei != NULL; ) { struct lnode *tmp; free(lnodei->str); regfree(&lnodei->reg); tmp = lnodei; lnodei = lnodei->next; free(tmp); } return Err; }