// // aegis - project change supervisor // Copyright (C) 2006, 2008, 2012, 2014 Peter Miller // Copyright (C) 2005, 2007 Walter Franzini // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published // by the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum { arglex_token_extract, arglex_token_create }; static arglex_table_ty argtab[] = { { "-EXTract", arglex_token_extract }, { "-CREate", arglex_token_create }, { "-File", arglex_token_file }, { "-List", arglex_token_list }, { "-Change_Directory", arglex_token_change_directory}, ARGLEX_END_MARKER }; static input_cpio::pointer input_cpio_mime(const input::pointer &ip) { input::pointer ifp = ip; rfc822 hdr; hdr.load(ifp, true); nstring s = hdr.get("mime-version"); if (!s.empty()) { s = hdr.get("content-type"); if (s != "application/aegis-change-set") ifp->fatal_error("wrong content type"); } // // Deal with the content encoding. // s = hdr.get("content-transfer-encoding"); if (!s.empty()) { static nstring base64("base64"); static nstring uuencode("uuencode"); // // We could cope with other encodings here, // if we ever need to. // if (s == base64) { // // The rest of the input is in base64 encoding. // ifp = input_base64::create(ifp); } else if (s == uuencode) { // // The rest of the input is uuencoded. // ifp = input_uudecode::create(ifp); } else { sub_context_ty sc; sc.var_set_string("Name", s); string_ty *tmp = sc.subst_intl(i18n("content transfer encoding $name unknown")); ifp->fatal_error(tmp->str_text); str_free(tmp); } } // // The contents we are interested in are // a gzipped cpio archive. // ifp = input_gunzip::create_if_candidate(ifp); ifp = input_bunzip2::create_if_candidate(ifp); input_cpio::pointer cpio_p = input_cpio::create(ifp); return cpio_p; } static int cpio_create(const nstring &cwd, const nstring &archive_name, const nstring_list &file_list) { if (archive_name.empty()) fatal_raw("empty archive name"); if (file_list.empty()) fatal_raw("empty list"); for (size_t n = 0; n < file_list.size(); ++n) { nstring ifn = file_list.get(n); nstring abs_path = os_path_join(cwd, ifn); if (ifn.empty()) fatal_raw("empty file name"); os_become_orig(); if (!os_exists(abs_path) || os_isa_special_file(abs_path.get_ref())) fatal_raw("bad file: %s", ifn.c_str()); os_become_undo(); } os_become_orig(); int archive_exists = os_exists(archive_name); os_become_undo(); if (archive_exists) fatal_raw("target already exists: %s", archive_name.c_str()); os_become_orig(); output::pointer ofp = output_file::binary_open(archive_name); output_cpio::pointer cpio_p = output_cpio::create(ofp, (time_t)0); for (size_t n = 0; n < file_list.size(); ++n) { nstring abs_path = os_path_join(cwd, file_list[n]); trace_nstring(file_list[n]); input::pointer ifp = input_file::open(abs_path); int len = ifp->length(); output::pointer os = cpio_p->child(file_list[n], len); os << ifp; } cpio_p.reset(); os_become_undo(); return 0; } static int cpio_list(const nstring &, const nstring &archive, const nstring_list &) { os_become_orig(); input::pointer ifp = input_file::open(archive); input_cpio::pointer cpio_p = input_cpio_mime(ifp); for (;;) { nstring ofn; input::pointer ifp2 = cpio_p->child(ofn); if (!ifp2) break; printf("%s\n", ofn.c_str()); output::pointer nowhere = output_bit_bucket::create(); nowhere << ifp2; } cpio_p.reset(); os_become_undo(); return 0; } static int cpio_extract(const nstring& root, const nstring& archive, const nstring_list&) { os_become_orig(); input::pointer ifp = input_file::open(archive); input_cpio::pointer cpio_p = input_cpio_mime(ifp); for (;;) { nstring ofn; input::pointer ifp2 = cpio_p->child(ofn); if (!ifp2) break; nstring abs_path = os_path_join(root, ofn); os_mkdir_between(root, ofn, 0755); output::pointer ofp = output_file::open(abs_path); ofp << ifp2; } cpio_p.reset(); os_become_undo(); return 0; } static void usage(void) { exit(EXIT_FAILURE); } // // test_cpio [ -extract | -create infile1 infile2 ... ] // // Extract operation: // // * the archive is read from stdin // * the file are extracted in the current directory // * if needed directory will be created // // % test_cpio -extract -file archive.cpio // // Create operation: // // * the archive will be written to stdout; // * the file to add to the archive are taken from the command file; // // % test_cpio -create -file archive.cpio file1 file2 .... // int main(int argc, char **argv) { nstring directory; nstring archive; nstring_list ifn; nstring cd; int (*func) (const nstring&, const nstring&, const nstring_list&); arglex_init(argc, argv, argtab); arglex(); os_become_init_mortal(); func = 0; while (arglex_token != arglex_token_eoln) { switch (arglex_token) { default: generic_argument(usage); continue; case arglex_token_file: arglex(); if (arglex_token != arglex_token_string) option_needs_string(arglex_token_file, usage); archive = arglex_value.alv_string; trace_nstring(archive); break; case arglex_token_change_directory: arglex(); if (arglex_token != arglex_token_string) option_needs_string(arglex_token_file, usage); cd = arglex_value.alv_string; break; case arglex_token_string: ifn.push_back(arglex_value.alv_string); break; case arglex_token_extract: func = cpio_extract; break; case arglex_token_create: func = cpio_create; break; case arglex_token_list: func = cpio_list; break; } arglex(); } trace_nstring(archive); int ret = 1; if (cd.empty()) cd = "."; if (func) ret = func(cd, archive, ifn); else usage(); exit(ret ? EXIT_FAILURE : EXIT_SUCCESS); } // vim: set ts=8 sw=4 et :