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; }
int main(int argc, char *argv[]) { int ret; char *filename = NULL; char command = 0, c; char **args; const char *tocfile = NULL; int arglen, i, err; xar_t x; int loptind = 0; int required_dash_f = 0; /* This release requires us to use -f */ struct lnode *tmp; long int longtmp; struct option o[] = { {"toc-cksum", 1, 0, 1}, {"dump-toc", 1, 0, 'd'}, {"compression", 1, 0, 2}, {"list-subdocs", 0, 0, 3}, {"help", 0, 0, 'h'}, {"version", 0, 0, 4}, {"dump-header", 0, 0, 5}, {"extract-subdoc", 1, 0, 6}, {"exclude", 1, 0, 7}, {"rsize", 1, 0, 8}, {"coalesce-heap", 0, 0, 9}, {"link-same", 0, 0, 10}, {"no-compress", 1, 0, 11}, {"prop-include", 1, 0, 12}, {"prop-exclude", 1, 0, 13}, {"distribution", 0, 0, 14}, {"keep-existing", 0, 0, 15}, {"keep-setuid", 0, 0, 16}, {"compression-args", 1, 0, 17}, { 0, 0, 0, 0} }; if( argc < 2 ) { usage(argv[0]); exit(1); } while( (c = getopt_long(argc, argv, "axcC:vtjzf:hpPln:s:d:vk", o, &loptind)) != -1 ) { switch(c) { case 1 : if( !optarg ) { usage(argv[0]); exit(1); } if( (strcmp(optarg, XAR_OPT_VAL_NONE) != 0) && (strcmp(optarg, XAR_OPT_VAL_SHA1) != 0) && (strcmp(optarg, XAR_OPT_VAL_MD5) != 0) ) { usage(argv[0]); exit(1); } Toccksum = optarg; break; case 2 : if( !optarg ) { usage(argv[0]); exit(1); } if( (strcmp(optarg, XAR_OPT_VAL_NONE) != 0) && (strcmp(optarg, XAR_OPT_VAL_GZIP) != 0) && (strcmp(optarg, XAR_OPT_VAL_BZIP) != 0) && (strcmp(optarg, XAR_OPT_VAL_LZMA) != 0) ) { usage(argv[0]); exit(1); } Compression = optarg; break; case 3 : if( command && (command != 3) ) { fprintf(stderr, "Conflicting commands specified\n"); exit(1); } command = 3; break; case 4 : print_version(); exit(0); case 'd': if( !optarg ) { usage(argv[0]); exit(1); } tocfile = optarg; command = 'd'; break; case 5 : command = 5; break; case 6 : SubdocName = optarg; asprintf(&Subdoc, "%s.xml", SubdocName); if( !command ) command = 6; break; case 7 : tmp = malloc(sizeof(struct lnode)); tmp->str = optarg; 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( Exclude == NULL ) { Exclude = tmp; Exclude_Tail = tmp; } else { Exclude_Tail->next = tmp; Exclude_Tail = tmp; } break; case 8 : if ( !optarg ) { usage(argv[0]); exit(1); } longtmp = strtol(optarg, NULL, 10); if( (((longtmp == LONG_MIN) || (longtmp == LONG_MAX)) && (errno == ERANGE)) || (longtmp < 1) ) { fprintf(stderr, "Invalid rsize value: %s\n", optarg); exit(5); } Rsize = optarg; break; case 9 : Coalesce = 1; break; case 10 : LinkSame = 1; break; case 11 : tmp = malloc(sizeof(struct lnode)); tmp->str = optarg; 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( NoCompress == NULL ) { NoCompress = tmp; NoCompress_Tail = tmp; } else { NoCompress_Tail->next = tmp; NoCompress_Tail = tmp; } break; case 12 : tmp = malloc(sizeof(struct lnode)); tmp->str = optarg; tmp->next = NULL; if( PropInclude == NULL ) { PropInclude = tmp; PropInclude_Tail = tmp; } else { PropInclude_Tail->next = tmp; PropInclude_Tail = tmp; } break; case 13 : tmp = malloc(sizeof(struct lnode)); tmp->str = optarg; tmp->next = NULL; if( PropExclude == NULL ) { PropExclude = tmp; PropExclude_Tail = tmp; } else { PropExclude_Tail->next = tmp; PropExclude_Tail = tmp; } break; case 14 : { char *props[] = { "type", "data", "mode", "name" }; int i; for( i = 0; i < 4; i++ ) { tmp = malloc(sizeof(struct lnode)); tmp->str = strdup(props[i]); tmp->next = NULL; if( PropInclude == NULL ) { PropInclude = tmp; PropInclude_Tail = tmp; } else { PropInclude_Tail->next = tmp; PropInclude_Tail = tmp; } } } break; case 'k': case 15 : NoOverwrite++; break; case 16 : SaveSuid++; break; case 17 : CompressionArg = optarg; break; case 'C': if( !optarg ) { usage(argv[0]); exit(1); } Chdir = optarg; break; case 'c': case 'x': case 't': if( command && (command != 's') ) { usage(argv[0]); fprintf(stderr, "Conflicting command flags: %c and %c specified\n", c, command); exit(1); } if( c == 't' ) List = 1; command = c; break; case 'a': Compression = "lzma"; break; case 'j': Compression = "bzip2"; break; case 'z': Compression = "gzip"; break; case 'f': required_dash_f = 1; filename = optarg; break; case 'p': Perms = SYMBOLIC; break; case 'P': Perms = NUMERIC; break; case 'l': Local = 1; break; case 'n': SubdocName = optarg; break; case 's': Subdoc = optarg; if( !command ) command = 's'; break; case 'v': Verbose++; break; case 'h': default: usage(argv[0]); exit(1); } } if (! required_dash_f) { usage(argv[0]); fprintf(stderr, "\n -f option is REQUIRED\n"); exit(1); } switch(command) { case 5 : return dump_header(filename); case 3 : return list_subdocs(filename); case 'c': if( optind == argc ) { usage(argv[0]); fprintf(stderr, "No files to operate on.\n"); exit(1); } arglen = argc - optind; args = malloc(sizeof(char*) * (arglen+1)); memset(args, 0, sizeof(char*) * (arglen+1)); for( i = 0; i < arglen; i++ ) args[i] = strdup(argv[optind + i]); return archive(filename, arglen, args); case 'd': if( !tocfile ) { usage(argv[0]); exit(1); } return dumptoc(filename, tocfile); case 'x': arglen = argc - optind; args = malloc(sizeof(char*) * (arglen+1)); for( i = 0; i < arglen; i++ ) args[i] = strdup(argv[optind + i]); args[i] = NULL; return extract(filename, arglen, args); case 't': arglen = argc - optind; args = calloc(sizeof(char*) * (arglen+1),1); for( i = 0; i < arglen; i++ ) args[i] = strdup(argv[optind + i]); ret = list(filename, arglen, args); for( i = 0; i < arglen; i++ ) free(args[i]); case 6 : case 's': 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); extract_subdoc(x, SubdocName); xar_close(x); exit(Err); break; default: usage(argv[0]); fprintf(stderr, "Unrecognized command.\n"); exit(1); } /* unreached */ exit(0); }
int main(int argc, char *argv[]) { char *filename = NULL; char *sig_path = NULL; char *cert_path = NULL; char command = 0, c; char **args; const char *tocfile = NULL; int arglen, i, err; xar_t x; int loptind = 0; int required_dash_f = 0; /* This release requires us to use -f */ struct lnode *tmp; long int longtmp; struct stat stat_struct; struct option o[] = { {"toc-cksum", 1, 0, 1}, {"dump-toc", 1, 0, 'd'}, {"compression", 1, 0, 2}, {"list-subdocs", 0, 0, 3}, {"help", 0, 0, 'h'}, {"version", 0, 0, 4}, {"dump-header", 0, 0, 5}, {"extract-subdoc", 1, 0, 6}, {"exclude", 1, 0, 7}, {"rsize", 1, 0, 8}, {"coalesce-heap", 0, 0, 9}, {"link-same", 0, 0, 10}, {"no-compress", 1, 0, 11}, {"sig-size", 1, 0, 12}, {"data-to-sign", 1, 0, 13}, {"sig-offset", 1, 0, 14}, {"leaf-cert-loc", 1, 0, 15}, {"intermediate-cert-loc", 1, 0, 16}, {"extract-data-to-sign", 0, 0, 17}, {"sign", 0, 0, 18}, {"replace-sign", 0, 0, 19}, {"inject-sig", 1, 0, 20}, {"extract-certs", 1, 0, 21}, { 0, 0, 0, 0} }; if( argc < 2 ) { usage(argv[0]); exit(1); } while( (c = getopt_long(argc, argv, "xcvtf:hpPln:s:d:v", o, &loptind)) != -1 ) { switch(c) { case 1 : if( !optarg ) { usage(argv[0]); exit(1); } if( (strcmp(optarg, XAR_OPT_VAL_NONE) != 0) && (strcmp(optarg, XAR_OPT_VAL_SHA1) != 0) && (strcmp(optarg, XAR_OPT_VAL_MD5) != 0) ) { usage(argv[0]); exit(1); } Toccksum = optarg; break; case 2 : if( !optarg ) { usage(argv[0]); exit(1); } if( (strcmp(optarg, XAR_OPT_VAL_NONE) != 0) && (strcmp(optarg, XAR_OPT_VAL_GZIP) != 0) && (strcmp(optarg, XAR_OPT_VAL_BZIP) != 0) ) { usage(argv[0]); exit(1); } Compression = optarg; break; case 3 : if( command && (command != 3) ) { fprintf(stderr, "Conflicting commands specified\n"); exit(1); } command = 3; break; case 4 : print_version(); exit(0); case 'd': if( !optarg ) { usage(argv[0]); exit(1); } tocfile = optarg; command = 'd'; break; case 5 : command = 5; break; case 6 : SubdocName = optarg; asprintf(&Subdoc, "%s.xml", SubdocName); if( !command ) command = 6; break; case 7 : tmp = malloc(sizeof(struct lnode)); tmp->str = optarg; 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( Exclude == NULL ) { Exclude = tmp; Exclude_Tail = tmp; } else { Exclude_Tail->next = tmp; Exclude_Tail = tmp; } break; case 8 : if ( !optarg ) { usage(argv[0]); exit(1); } longtmp = strtol(optarg, NULL, 10); if( (((longtmp == LONG_MIN) || (longtmp == LONG_MAX)) && (errno == ERANGE)) || (longtmp < 1) ) { fprintf(stderr, "Invalid rsize value: %s\n", optarg); exit(5); } Rsize = optarg; break; case 9 : Coalesce = 1; break; case 10 : LinkSame = 1; break; case 11 : tmp = malloc(sizeof(struct lnode)); tmp->str = optarg; 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( NoCompress == NULL ) { NoCompress = tmp; NoCompress_Tail = tmp; } else { NoCompress_Tail->next = tmp; NoCompress_Tail = tmp; } break; case 12 : if( !optarg ) { usage(argv[0]); exit(1); } SigSize = strtol(optarg, (char **)NULL, 10); break; case 13 : if( !optarg ) { usage(argv[0]); exit(1); } DataToSignDumpPath = optarg; break; case 14 : if( !optarg ) { usage(argv[0]); exit(1); } SigOffsetDumpPath = optarg; break; case 15 : if( !optarg ) { usage(argv[0]); exit(1); } LeafCertPath = optarg; break; case 16 : if( !optarg ) { usage(argv[0]); exit(1); } IntermediateCertPath = optarg; break; case 17 : // extract-data-to-sign command = 'e'; break; case 18 : // sign DoSign = 1; break; case 19 : // replace-sign command = 'r'; break; case 20 : // inject signature if( !optarg ) { usage(argv[0]); exit(1); } sig_path = optarg; command = 'i'; break; case 21 : // extract-certs if( !optarg ) { usage(argv[0]); exit(1); } cert_path = optarg; stat(cert_path, &stat_struct); if (!(stat_struct.st_mode & S_IFDIR)) { usage(argv[0]); fprintf(stderr, "%s is not a directory.\n", cert_path); exit(1); } command = 'j'; break; case 'c': case 'x': case 't': if( command && (command != 's') ) { usage(argv[0]); fprintf(stderr, "Conflicting command flags: %c and %c specified\n", c, command); exit(1); } if( c == 't' ) Verbose++; command = c; break; case 'f': required_dash_f = 1; filename = optarg; break; case 'p': Perms = SYMBOLIC; break; case 'P': Perms = NUMERIC; break; case 'l': Local = 1; break; case 'n': SubdocName = optarg; break; case 's': Subdoc = optarg; if( !command ) command = 's'; break; case 'v': Verbose++; break; case 'h': default: usage(argv[0]); exit(1); } } if (! required_dash_f) { usage(argv[0]); fprintf(stderr, "\n -f option is REQUIRED\n"); exit(1); } // extract-data-to-sign if ( (command == 'e') && ((!filename) || (!DataToSignDumpPath) || (!SigOffsetDumpPath)) ) { usage(argv[0]); exit(1); } if ( DoSign ) { if ( ( !SigSize || !LeafCertPath || !IntermediateCertPath ) || ((command != 'c') && (!filename)) ) { usage(argv[0]); exit(1); } if (!command) command = 'n'; } if (command == 'r') { /*if ( !SigSize || !LeafCertPath || !IntermediateCertPath || !filename) { usage(argv[0]); exit(1); } xar_t x = xar_open(filename, READ); if ( x == NULL ) { fprintf(stderr, "Could not open archive %s!\n", filename); exit(1); } xar_signature_t sig = xar_signature_first(x); if ( !sig ) { fprintf(stderr, "No signature found to replace.\n"); exit(E_NOSIG); } xar_close(x);*/ } if ((command == 'i') && ((!filename) || (!sig_path))) { usage(argv[0]); exit(1); } if ((command == 'j') && (!filename)) { usage(argv[0]); exit(1); } switch(command) { case 5 : return dump_header(filename); case 3 : return list_subdocs(filename); case 'c': if( optind == argc ) { usage(argv[0]); fprintf(stderr, "No files to operate on.\n"); exit(1); } arglen = argc - optind; args = malloc(sizeof(char*) * (arglen+1)); memset(args, 0, sizeof(char*) * (arglen+1)); for( i = 0; i < arglen; i++ ) args[i] = strdup(argv[optind + i]); return archive(filename, arglen, args); case 'd': if( !tocfile ) { usage(argv[0]); exit(1); } return dumptoc(filename, tocfile); case 'x': arglen = argc - optind; args = malloc(sizeof(char*) * (arglen+1)); for( i = 0; i < arglen; i++ ) args[i] = strdup(argv[optind + i]); args[i] = NULL; return extract(filename, arglen, args); case 't': arglen = argc - optind; args = malloc(sizeof(char*) * (arglen+1)); for( i = 0; i < arglen; i++ ) args[i] = strdup(argv[optind + i]); return list(filename, arglen, args); case 6 : case 's': 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); extract_subdoc(x, SubdocName); xar_close(x); exit(Err); break; case 'e': extract_data_to_sign(filename); exit(Err); case 'r': replace_sign(filename); exit(Err); case 'i': inject_signature(filename, sig_path); exit(Err); case 'n': belated_sign(filename); exit(Err); case 'j': extract_certs(filename, cert_path); exit(Err); default: usage(argv[0]); fprintf(stderr, "Unrecognized command.\n"); exit(1); } /* unreached */ exit(0); }
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; }