aboutsummaryrefslogtreecommitdiffstats
path: root/tools/gpgtar.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2010-06-07 13:33:02 +0000
committerWerner Koch <[email protected]>2010-06-07 13:33:02 +0000
commitbbe388b5db35be6ffece8ebd42f11372af016763 (patch)
tree73e1fe9697b969be66bd89953125010e5721efe1 /tools/gpgtar.c
parentPrint --version etc via estream (diff)
downloadgnupg-bbe388b5db35be6ffece8ebd42f11372af016763.tar.gz
gnupg-bbe388b5db35be6ffece8ebd42f11372af016763.zip
Add unfinished gpgtar.
Collected changes and ports of bug fixes from stable.
Diffstat (limited to 'tools/gpgtar.c')
-rw-r--r--tools/gpgtar.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/tools/gpgtar.c b/tools/gpgtar.c
new file mode 100644
index 000000000..555fe39dc
--- /dev/null
+++ b/tools/gpgtar.c
@@ -0,0 +1,361 @@
+/* gpgtar.c - A simple TAR implementation mainly useful for Windows.
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* GnuPG comes with a shell script gpg-zip which creates archive files
+ in the same format as PGP Zip, which is actually a USTAR format.
+ That is fine and works nicely on all Unices but for Windows we
+ don't have a compatible shell and the supply of tar programs is
+ limited. Given that we need just a few tar option and it is an
+ open question how many Unix concepts are to be mapped to Windows,
+ we might as well write our own little tar customized for use with
+ gpg. So here we go. */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+#include "i18n.h"
+#include "sysutils.h"
+#include "../common/openpgpdefs.h"
+
+#include "gpgtar.h"
+
+
+/* Constants to identify the commands and options. */
+enum cmd_and_opt_values
+ {
+ aNull = 0,
+ aEncrypt = 'e',
+ aDecrypt = 'd',
+ aSign = 's',
+
+ oSymmetric = 'c',
+ oRecipient = 'r',
+ oUser = 'u',
+ oOutput = 'o',
+ oQuiet = 'q',
+ oVerbose = 'v',
+ oNoVerbose = 500,
+
+ aSignEncrypt,
+ oSkipCrypto,
+ aList
+ };
+
+
+/* The list of commands and options. */
+static ARGPARSE_OPTS opts[] = {
+ ARGPARSE_group (300, N_("@Commands:\n ")),
+
+ ARGPARSE_c (aEncrypt, "encrypt", N_("create an archive")),
+ ARGPARSE_c (aDecrypt, "decrypt", N_("extract an archive")),
+ ARGPARSE_c (aSign, "sign", N_("create a signed archive")),
+ ARGPARSE_c (aList, "list-archive", N_("list an archive")),
+
+ ARGPARSE_group (301, N_("@\nOptions:\n ")),
+
+ ARGPARSE_s_n (oSymmetric, "symmetric", N_("use symmetric encryption")),
+ ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
+ ARGPARSE_s_s (oUser, "local-user",
+ N_("|USER-ID|use USER-ID to sign or decrypt")),
+ ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
+ ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
+ ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
+ ARGPARSE_s_n (oSkipCrypto, "skip-crypto", N_("skip the crypto processing")),
+
+ ARGPARSE_end ()
+};
+
+
+
+static void tar_and_encrypt (char **inpattern);
+static void decrypt_and_untar (const char *fname);
+static void decrypt_and_list (const char *fname);
+
+
+
+
+/* Print usage information and and provide strings for help. */
+static const char *
+my_strusage( int level )
+{
+ const char *p;
+
+ switch (level)
+ {
+ case 11: p = "gpgtar (GnuPG)";
+ break;
+ case 13: p = VERSION; break;
+ case 17: p = PRINTABLE_OS_NAME; break;
+ case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
+
+ case 1:
+ case 40:
+ p = _("Usage: gpgtar [options] [files] [directories] (-h for help)");
+ break;
+ case 41:
+ p = _("Syntax: gpgtar [options] [files] [directories]\n"
+ "Encrypt or sign files into an archive\n");
+ break;
+
+ default: p = NULL; break;
+ }
+ return p;
+}
+
+
+static void
+set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
+{
+ enum cmd_and_opt_values cmd = *ret_cmd;
+
+ if (!cmd || cmd == new_cmd)
+ cmd = new_cmd;
+ else if (cmd == aSign && new_cmd == aEncrypt)
+ cmd = aSignEncrypt;
+ else if (cmd == aEncrypt && new_cmd == aSign)
+ cmd = aSignEncrypt;
+ else
+ {
+ log_error (_("conflicting commands\n"));
+ exit (2);
+ }
+
+ *ret_cmd = cmd;
+}
+
+
+
+/* gpgtar main. */
+int
+main (int argc, char **argv)
+{
+ ARGPARSE_ARGS pargs;
+ const char *fname;
+ int no_more_options = 0;
+ enum cmd_and_opt_values cmd = 0;
+ int skip_crypto = 0;
+
+ assert (sizeof (struct ustar_raw_header) == 512);
+
+ gnupg_reopen_std ("gpgtar");
+ set_strusage (my_strusage);
+ log_set_prefix ("gpgtar", 1);
+
+ /* Make sure that our subsystems are ready. */
+ i18n_init();
+ init_common_subsystems (&argc, &argv);
+
+ /* Parse the command line. */
+ pargs.argc = &argc;
+ pargs.argv = &argv;
+ pargs.flags = ARGPARSE_FLAG_KEEP;
+ while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
+ {
+ switch (pargs.r_opt)
+ {
+ case oOutput: opt.outfile = pargs.r.ret_str; break;
+ case oQuiet: opt.quiet = 1; break;
+ case oVerbose: opt.verbose++; break;
+ case oNoVerbose: opt.verbose = 0; break;
+
+ case aList:
+ case aDecrypt:
+ case aEncrypt:
+ case aSign:
+ set_cmd (&cmd, pargs.r_opt);
+ break;
+
+ case oSymmetric:
+ set_cmd (&cmd, aEncrypt);
+ opt.symmetric = 1;
+ break;
+
+ case oSkipCrypto:
+ skip_crypto = 1;
+ break;
+
+ default: pargs.err = 2; break;
+ }
+ }
+
+ if (log_get_errorcount (0))
+ exit (2);
+
+ switch (cmd)
+ {
+ case aList:
+ if (argc > 1)
+ usage (1);
+ fname = argc ? *argv : NULL;
+ if (skip_crypto)
+ gpgtar_list (fname);
+ else
+ decrypt_and_list (fname);
+ break;
+
+ case aEncrypt:
+ if (!argc)
+ usage (1);
+ if (skip_crypto)
+ gpgtar_create (argv);
+ else
+ tar_and_encrypt (argv);
+ break;
+
+ case aDecrypt:
+ if (argc != 1)
+ usage (1);
+ if (opt.outfile)
+ log_info ("note: ignoring option --output\n");
+ fname = argc ? *argv : NULL;
+ if (skip_crypto)
+ gpgtar_extract (fname);
+ else
+ decrypt_and_untar (fname);
+ break;
+
+ default:
+ log_error (_("invalid command (there is no implicit command)\n"));
+ break;
+ }
+
+ return log_get_errorcount (0)? 1:0;
+}
+
+
+/* Read the next record from STREAM. RECORD is a buffer provided by
+ the caller and must be at leadt of size RECORDSIZE. The function
+ return 0 on success and and error code on failure; a diagnostic
+ printed as well. Note that there is no need for an EOF indicator
+ because a tarball has an explicit EOF record. */
+gpg_error_t
+read_record (estream_t stream, void *record)
+{
+ gpg_error_t err;
+ size_t nread;
+
+ nread = es_fread (record, 1, RECORDSIZE, stream);
+ if (nread != RECORDSIZE)
+ {
+ err = gpg_error_from_syserror ();
+ if (es_ferror (stream))
+ log_error ("error reading `%s': %s\n",
+ es_fname_get (stream), gpg_strerror (err));
+ else
+ log_error ("error reading `%s': premature EOF "
+ "(size of last record: %zu)\n",
+ es_fname_get (stream), nread);
+ }
+ else
+ err = 0;
+
+ return err;
+}
+
+
+/* Write the RECORD of size RECORDSIZE to STREAM. FILENAME is the
+ name of the file used for diagnostics. */
+gpg_error_t
+write_record (estream_t stream, const void *record)
+{
+ gpg_error_t err;
+ size_t nwritten;
+
+ nwritten = es_fwrite (record, 1, RECORDSIZE, stream);
+ if (nwritten != RECORDSIZE)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error writing `%s': %s\n",
+ es_fname_get (stream), gpg_strerror (err));
+ }
+ else
+ err = 0;
+
+ return err;
+}
+
+
+/* Return true if FP is an unarmored OpenPGP message. Note that this
+ fucntion reads a few bytes from FP but pushes them back. */
+static int
+openpgp_message_p (estream_t fp)
+{
+ int ctb;
+
+ ctb = es_getc (fp);
+ if (ctb != EOF)
+ {
+ if (es_ungetc (ctb, fp))
+ log_fatal ("error ungetting first byte: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+
+ if ((ctb & 0x80))
+ {
+ switch ((ctb & 0x40) ? (ctb & 0x3f) : ((ctb>>2)&0xf))
+ {
+ case PKT_MARKER:
+ case PKT_SYMKEY_ENC:
+ case PKT_ONEPASS_SIG:
+ case PKT_PUBKEY_ENC:
+ case PKT_SIGNATURE:
+ case PKT_COMMENT:
+ case PKT_OLD_COMMENT:
+ case PKT_PLAINTEXT:
+ case PKT_COMPRESSED:
+ case PKT_ENCRYPTED:
+ return 1; /* Yes, this seems to be an OpenPGP message. */
+ default:
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+
+
+static void
+tar_and_encrypt (char **inpattern)
+{
+
+}
+
+
+
+static void
+decrypt_and_untar (const char *fname)
+{
+
+
+}
+
+
+
+static void
+decrypt_and_list (const char *fname)
+{
+
+}