aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2005-06-21 02:12:44 +0000
committerMike Frysinger <vapier@gentoo.org>2005-06-21 02:12:44 +0000
commit37f84070ad5d1dfa12985b0a022fdfed49cc6ec0 (patch)
tree5edc41de769f4df6b81a0a6c1af2a6a803002a72 /qtbz2.c
parenttemplate for new applets (diff)
downloadportage-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.c283
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;
+}