diff options
author | Mike Frysinger <vapier@gentoo.org> | 2005-06-21 02:12:44 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2005-06-21 02:12:44 +0000 |
commit | 37f84070ad5d1dfa12985b0a022fdfed49cc6ec0 (patch) | |
tree | 5edc41de769f4df6b81a0a6c1af2a6a803002a72 /qtbz2.c | |
parent | template for new applets (diff) | |
download | portage-utils-37f84070ad5d1dfa12985b0a022fdfed49cc6ec0.tar.gz portage-utils-37f84070ad5d1dfa12985b0a022fdfed49cc6ec0.tar.bz2 portage-utils-37f84070ad5d1dfa12985b0a022fdfed49cc6ec0.zip |
import a tbz2tool applet
Diffstat (limited to 'qtbz2.c')
-rw-r--r-- | qtbz2.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/qtbz2.c b/qtbz2.c new file mode 100644 index 00000000..c33f2b0a --- /dev/null +++ b/qtbz2.c @@ -0,0 +1,283 @@ +/* + * Copyright 2005 Gentoo Foundation + * Distributed under the terms of the GNU General Public License v2 + * $Header: /var/cvsroot/gentoo-projects/portage-utils/qtbz2.c,v 1.1 2005/06/21 02:12:44 vapier Exp $ + * + * 2005 Ned Ludd - <solar@gentoo.org> + * 2005 Mike Frysinger - <vapier@gentoo.org> + * + ******************************************************************** + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + * + */ + + + +/* +# The format for a tbz2/xpak: +# +# tbz2: tar.bz2 + xpak + (xpak_offset) + "STOP" +# xpak: "XPAKPACK" + (index_len) + (data_len) + index + data + "XPAKSTOP" +# index: (pathname_len) + pathname + (data_offset) + (data_len) +# index entries are concatenated end-to-end. +# data: concatenated data chunks, end-to-end. +# +# [tarball]XPAKPACKIIIIDDDD[index][data]XPAKSTOPOOOOSTOP +# +# (integer) == encodeint(integer) ===> 4 characters (big-endian copy) +# '+' means concatenate the fields ===> All chunks are strings +*/ +#define TBZ2_END_MSG "STOP" +#define TBZ2_END_MSG_LEN 4 +#define TBZ2_END_LEN (4 + TBZ2_END_MSG_LEN) + + + +#define QTBZ2_FLAGS "js" COMMON_FLAGS +static struct option const qtbz2_long_opts[] = { + {"join", no_argument, NULL, 'j'}, + {"split", no_argument, NULL, 's'}, + COMMON_LONG_OPTS +}; +static const char *qtbz2_opts_help[] = { + "Join tar.bz2 + xpak into a tbz2", + "Split a tbz2 into a tar.bz2 + xpak", + COMMON_OPTS_HELP +}; +#define qtbz2_usage(ret) usage(ret, QTBZ2_FLAGS, qtbz2_long_opts, qtbz2_opts_help, APPLET_QTBZ2) + + + +void _tbz2_copy_file(FILE *src, FILE *dst); +void _tbz2_copy_file(FILE *src, FILE *dst) +{ + int count = 1; + unsigned char buffer[BUFSIZE*32]; + while (count) { + count = fread(buffer, 1, sizeof(buffer), src); + fwrite(buffer, 1, count, dst); + } +} + +char tbz2_compose(const char *tarbz2, const char *xpak, const char *tbz2); +char tbz2_compose(const char *tarbz2, const char *xpak, const char *tbz2) +{ + FILE *out, *in_tarbz2, *in_xpak; + unsigned char tbz2_tail[TBZ2_END_LEN]; + struct stat st; + char ret = 1; + + /* open tbz2 output */ + if ((out = fopen(tbz2, "w")) == NULL) + return ret; + /* open tar.bz2 input */ + if ((in_tarbz2 = fopen(tarbz2, "r")) == NULL) { + fclose(out); + return ret; + } + /* open xpak input */ + if ((in_xpak = fopen(xpak, "r")) == NULL) { + fclose(out); + fclose(in_tarbz2); + return ret; + } + fstat(fileno(in_xpak), &st); + + /* save [tarball] */ + _tbz2_copy_file(in_tarbz2, out); + fclose(in_tarbz2); + /* save [xpak] */ + _tbz2_copy_file(in_xpak, out); + fclose(in_xpak); + + /* save tbz2 tail: OOOOSTOP */ + tbz2_tail[0] = ((st.st_size) & 0xff000000) >> 24; + tbz2_tail[1] = ((st.st_size) & 0x00ff0000) >> 16; + tbz2_tail[2] = ((st.st_size) & 0x0000ff00) >> 8; + tbz2_tail[3] = (st.st_size) & 0x000000ff; + memcpy(tbz2_tail + 4, TBZ2_END_MSG, TBZ2_END_MSG_LEN); + fwrite(tbz2_tail, 1, TBZ2_END_LEN, out); + + fclose(out); + ret = 0; + return ret; +} + +#define _TBZ2_MIN(a,b) (a < b ? : b) +void _tbz2_write_file(FILE *src, const char *dst, size_t len); +void _tbz2_write_file(FILE *src, const char *dst, size_t len) +{ + unsigned char buffer[BUFSIZE*32]; + size_t this_write; + FILE *out; + + if ((out = fopen(dst, "w")) == NULL) + return; + + do { + this_write = fread(buffer, 1, _TBZ2_MIN(len, sizeof(buffer)), src); + fwrite(buffer, 1, this_write, out); + len -= this_write; + } while (len && this_write); + + fclose(out); +} + +char tbz2_decompose(const char *tbz2, const char *tarbz2, const char *xpak); +char tbz2_decompose(const char *tbz2, const char *tarbz2, const char *xpak) +{ + FILE *in; + unsigned char tbz2_tail[TBZ2_END_LEN]; + long xpak_size, tarbz2_size; + struct stat st; + char ret = 1; + + /* open tbz2 input */ + if ((in = fopen(tbz2, "r")) == NULL) + return ret; + fstat(fileno(in), &st); + /* verify the tail signature */ + if (fseek(in, -TBZ2_END_LEN, SEEK_END) != 0) + goto close_in_and_ret; + if (fread(tbz2_tail, 1, TBZ2_END_LEN, in) != TBZ2_END_LEN) + goto close_in_and_ret; + if (memcmp(tbz2_tail + 4, TBZ2_END_MSG, TBZ2_END_MSG_LEN)) { + warn("%s: Invalid tbz2", tbz2); + goto close_in_and_ret; + } + + /* calculate xpak's size */ + xpak_size = 0; + xpak_size += (tbz2_tail[0] << 24); + xpak_size += (tbz2_tail[1] << 16); + xpak_size += (tbz2_tail[2] << 8); + xpak_size += (tbz2_tail[3]); + /* calculate tarbz2's size */ + tarbz2_size = st.st_size - xpak_size - TBZ2_END_LEN; + + /* reset to the start of the tbz2 */ + rewind(in); + /* dump the tar.bz2 */ + _tbz2_write_file(in, tarbz2, tarbz2_size); + /* dump the xpak */ + _tbz2_write_file(in, xpak, xpak_size); + + ret = 0; +close_in_and_ret: + fclose(in); + return ret; +} + +int qtbz2_main(int argc, char **argv) +{ + int i; + char action = 0; + char *heap_tbz2, *heap_xpak, *heap_tarbz2; + char *tbz2, *xpak, *tarbz2; + + DBG("argc=%d argv[0]=%s argv[1]=%s", + argc, argv[0], argc > 1 ? argv[1] : "NULL?"); + + while ((i = GETOPT_LONG(QTBZ2, qtbz2, "")) != -1) { + switch (i) { + COMMON_GETOPTS_CASES(qtbz2) + + case 'j': action = 1; break; + case 's': action = 2; break; + } + } + if (optind == argc) { + switch (action) { + case 1: join_usage: + err("Join usage: <input tar.bz2> <input xpak> [<output tbz2>]"); + case 2: split_usage: + err("Split usage <input tbz2> [<output tar.bz2> <output xpak>]"); + default: qtbz2_usage(EXIT_FAILURE); + } + } + + heap_tbz2 = heap_xpak = heap_tarbz2 = NULL; + tbz2 = xpak = tarbz2 = NULL; + + if (action == 0) { + if (strstr(argv[optind], ".tar.bz2") != NULL) + action = 1; + else if (strstr(argv[optind], ".tbz2") != NULL) + action = 2; + else + qtbz2_usage(EXIT_FAILURE); + } + + /* tbz2tool join .tar.bz2 .xpak .tbz2 */ + if (action == 1) { + /* grab the params if the user gave them */ + tarbz2 = argv[optind++]; + if (optind < argc) { + xpak = argv[optind++]; + if (optind < argc) + tbz2 = argv[optind]; + } + /* otherwise guess what they should be */ + if (!xpak) { + i = strlen(tarbz2); + if (i <= 5) goto join_usage; + xpak = heap_xpak = xstrdup(tarbz2); + strcpy(xpak+i-7, "xpak"); + } + if (!tbz2) { + i = strlen(tarbz2); + if (i <= 5) goto join_usage; + tbz2 = heap_tbz2 = xstrdup(tarbz2); + strcpy(tbz2+i-6, "bz2"); + } + + if (tbz2_compose(tarbz2, xpak, tbz2)) + warn("Could not compose '%s' and '%s'", tarbz2, xpak); + + /* tbz2tool split .tbz2 .tar.bz2 .xpak */ + } else { + /* grab the params if the user gave them */ + tbz2 = argv[optind++]; + if (optind < argc) { + tarbz2 = argv[optind++]; + if (optind < argc) + xpak = argv[optind]; + } + /* otherwise guess what they should be */ + if (!tarbz2) { + i = strlen(tbz2); + if (i <= 5) goto split_usage; + tarbz2 = heap_tarbz2 = xmalloc(i + 4); + strcpy(tarbz2, tbz2); + strcpy(tarbz2+i-3, "ar.bz2"); + } + if (!xpak) { + i = strlen(tbz2); + if (i <= 5) goto split_usage; + xpak = heap_xpak = xstrdup(tbz2); + strcpy(xpak+i-4, "xpak"); + } + + if (tbz2_decompose(tbz2, tarbz2, xpak)) + warn("Could not decompose '%s'", tbz2); + } + + if (heap_tbz2) free(heap_tbz2); + if (heap_xpak) free(heap_xpak); + if (heap_tarbz2) free(heap_tarbz2); + + return EXIT_SUCCESS; +} |