static int list(const char *filename, int arglen, char *args[]) { xar_t x; xar_iter_t i; xar_file_t f; x = xar_open(filename, READ); if( !x ) { fprintf(stderr, "Error opening xar archive: %s\n", filename); exit(1); } 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)) { print_file(f); } xar_iter_free(i); xar_close(x); return Err; }
std::map<std::string, std::string> Extract(std::string file, std::string prefix) { std::map<std::string, std::string> files; #ifdef HAVE_LIBXAR xar_t x; xar_iter_t xi; xar_file_t xf; xar_stream xs; char buffer[8192]; x = xar_open(file.c_str(), READ); if (x == nullptr) { std::cerr << "Could not open xar archive" << std::endl; } xi = xar_iter_new(); if (xi == nullptr) { xar_close(x); std::cerr << "Could not read xar archive" << std::endl; } for (xf = xar_file_first(x, xi); xf != nullptr; xf = xar_file_next(xi)) { char *path = xar_get_path(xf); const char *type; xar_prop_get(xf, "type", &type); if (type == nullptr) { std::cerr << "File has no type" << std::endl; free(path); continue; } if (std::strcmp(type, "file") != 0) { free(path); continue; } if (xar_extract_tostream_init(x, xf, &xs) != XAR_STREAM_OK) { std::cerr << "Error initializing stream" << std::endl; free(path); continue; } const std::string fileName = prefix + util::uuid::UuidToString(util::uuid::GenerateUUID()); // Write bitcode to file std::FILE *output = std::fopen(fileName.c_str(), "wb"); if (output == nullptr) { std::cerr << "Error opening output file" << std::endl; continue; } xs.avail_out = sizeof(buffer); xs.next_out = buffer; int32_t ret; while ((ret = xar_extract_tostream(&xs)) != XAR_STREAM_END) { if (ret == XAR_STREAM_ERR) { std::cerr << "Error extracting stream" << std::endl; break; } std::fwrite(buffer, sizeof(char), sizeof(buffer) - xs.avail_out, output); xs.avail_out = sizeof(buffer); xs.next_out = buffer; } if (xar_extract_tostream_end(&xs) != XAR_STREAM_OK) { std::cerr << "Error ending stream" << std::endl; } std::fclose(output); // Add to list of extracted files files[std::string(path)] = fileName; free(path); } xar_iter_free(xi); xar_close(x); #endif return files; }
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 list(const char *filename, int arglen, char *args[]) { xar_t x; xar_iter_t i; xar_file_t f; int argi = 0; struct lnode *list_files = NULL; struct lnode *list_tail = NULL; struct lnode *lnodei = 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( list_files == NULL ) { list_files = tmp; list_tail = tmp; } else { list_tail->next = tmp; list_tail = tmp; } } x = xar_open(filename, READ); if( !x ) { fprintf(stderr, "Error opening xar archive: %s\n", filename); exit(1); } 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; if( args[0] ) { char *path = xar_get_path(f); if (xar_path_issane(path) == 0) { fprintf(stderr, "Warning, archive contains invalid path: %s\n", path); free(path); continue; } for(lnodei = list_files; lnodei != NULL; lnodei = lnodei->next) { int list_match = 1; list_match = regexec(&lnodei->reg, path, 0, NULL, 0); if( !list_match ) { matched = 1; break; } } free(path); } else { matched = 1; } if( matched ) print_file(x, f); } xar_iter_free(i); xar_close(x); for(lnodei = list_files; lnodei != NULL; ) { struct lnode *tmp; free(lnodei->str); regfree(&lnodei->reg); tmp = lnodei; lnodei = lnodei->next; free(tmp); } 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; }
int32_t xar_stat_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { const char *opt; int ret, fd; mode_t modet = 0; xar_prop_get(f, "type", &opt); if(opt && (strcmp(opt, "character special") == 0)) modet = S_IFCHR; if(opt && (strcmp(opt, "block special") == 0)) modet = S_IFBLK; if( modet ) { uint32_t major, minor; long long tmpll; dev_t devt; xar_prop_get(f, "device/major", &opt); tmpll = strtoll(opt, NULL, 10); if( ( (tmpll == LLONG_MIN) || (tmpll == LLONG_MAX) ) && (errno == ERANGE) ) return -1; if( (tmpll < 0) || (tmpll > 255) ) return -1; major = tmpll; xar_prop_get(f, "device/minor", &opt); tmpll = strtoll(opt, NULL, 10); if( ( (tmpll == LLONG_MIN) || (tmpll == LLONG_MAX) ) && (errno == ERANGE) ) return -1; if( (tmpll < 0) || (tmpll > 255) ) return -1; minor = tmpll; devt = xar_makedev(major, minor); unlink(file); if( mknod(file, modet, devt) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "mknod: Could not create character device"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } return 0; } if(opt && (strcmp(opt, "directory") == 0)) { ret = mkdir(file, 0700); if( (ret != 0) && (errno != EEXIST) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "stat: Could not create directory"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return ret; } return 0; } if(opt && (strcmp(opt, "symlink") == 0)) { xar_prop_get(f, "link", &opt); if( opt ) { unlink(file); ret = symlink(opt, file); if( ret != 0 ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "stat: Could not create symlink"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } return ret; } } if(opt && (strcmp(opt, "hardlink") == 0)) { xar_file_t tmpf; opt = xar_attr_get(f, "type", "link"); if( !opt ) return 0; if( strcmp(opt, "original") == 0 ) goto CREATEFILE; tmpf = xmlHashLookup(XAR(x)->link_hash, BAD_CAST(opt)); if( !tmpf ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "stat: Encountered hardlink with no original"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } unlink(file); if( link(XAR_FILE(tmpf)->fspath, file) != 0 ) { if( errno == ENOENT ) { xar_iter_t i; const char *ptr; i = xar_iter_new(x); for(ptr = xar_prop_first(tmpf, i); ptr; ptr = xar_prop_next(i)) { xar_iter_t a; const char *val = NULL; const char *akey, *aval; if( strncmp("data", ptr, 4) != 0 ) continue; if( xar_prop_get(tmpf, ptr, &val) ) continue; xar_prop_set(f, ptr, val); a = xar_iter_new(x); for(akey = xar_attr_first(tmpf, ptr, a); akey; akey = xar_attr_next(a)) { aval = xar_attr_get(tmpf, ptr, akey); xar_attr_set(f, ptr, akey, aval); } xar_iter_free(a); } xar_iter_free(i); xar_attr_set(f, "type", "link", "original"); return 0; } else { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "stat: Could not link hardlink to original"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } } return 0; } if(opt && (strcmp(opt, "fifo") == 0)) { unlink(file); if( mkfifo(file, 0) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "mkfifo: Could not create fifo"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } return 0; } /* skip sockets */ if(opt && (strcmp(opt, "socket") == 0)) { return 0; } CREATEFILE: unlink(file); fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0600); if( fd > 0 ) close(fd); return 0; }