common: Add a global variable to for the default error source.
[gnupg.git] / tools / gpgtar.c
1 /* gpgtar.c - A simple TAR implementation mainly useful for Windows.
2  * Copyright (C) 2010 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* GnuPG comes with a shell script gpg-zip which creates archive files
21    in the same format as PGP Zip, which is actually a USTAR format.
22    That is fine and works nicely on all Unices but for Windows we
23    don't have a compatible shell and the supply of tar programs is
24    limited.  Given that we need just a few tar option and it is an
25    open question how many Unix concepts are to be mapped to Windows,
26    we might as well write our own little tar customized for use with
27    gpg.  So here we go.  */
28
29 #include <config.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <assert.h>
35
36 #include "util.h"
37 #include "i18n.h"
38 #include "sysutils.h"
39 #include "../common/openpgpdefs.h"
40 #include "../common/init.h"
41
42 #include "gpgtar.h"
43
44
45 /* Constants to identify the commands and options. */
46 enum cmd_and_opt_values
47   {
48     aNull = 0,
49     aEncrypt    = 'e',
50     aDecrypt    = 'd',
51     aSign       = 's',
52     aList       = 't',
53
54     oSymmetric  = 'c',
55     oRecipient  = 'r',
56     oUser       = 'u',
57     oOutput     = 'o',
58     oQuiet      = 'q',
59     oVerbose    = 'v',
60     oFilesFrom  = 'T',
61     oNoVerbose  = 500,
62
63     aSignEncrypt,
64     oSkipCrypto,
65     oOpenPGP,
66     oCMS,
67     oSetFilename,
68     oNull
69   };
70
71
72 /* The list of commands and options. */
73 static ARGPARSE_OPTS opts[] = {
74   ARGPARSE_group (300, N_("@Commands:\n ")),
75
76   ARGPARSE_c (aEncrypt,   "encrypt", N_("create an archive")),
77   ARGPARSE_c (aDecrypt,   "decrypt", N_("extract an archive")),
78   ARGPARSE_c (aSign,      "sign",    N_("create a signed archive")),
79   ARGPARSE_c (aList,      "list-archive", N_("list an archive")),
80
81   ARGPARSE_group (301, N_("@\nOptions:\n ")),
82
83   ARGPARSE_s_n (oSymmetric, "symmetric", N_("use symmetric encryption")),
84   ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
85   ARGPARSE_s_s (oUser, "local-user",
86                 N_("|USER-ID|use USER-ID to sign or decrypt")),
87   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
88   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
89   ARGPARSE_s_n (oQuiet, "quiet",  N_("be somewhat more quiet")),
90   ARGPARSE_s_n (oSkipCrypto, "skip-crypto", N_("skip the crypto processing")),
91   ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
92   ARGPARSE_s_s (oFilesFrom, "files-from",
93                 N_("|FILE|get names to create from FILE")),
94   ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")),
95   ARGPARSE_s_n (oOpenPGP, "openpgp", "@"),
96   ARGPARSE_s_n (oCMS, "cms", "@"),
97
98   ARGPARSE_end ()
99 };
100
101
102 \f
103 static void tar_and_encrypt (char **inpattern);
104 static void decrypt_and_untar (const char *fname);
105 static void decrypt_and_list (const char *fname);
106
107
108
109 \f
110 /* Print usage information and and provide strings for help. */
111 static const char *
112 my_strusage( int level )
113 {
114   const char *p;
115
116   switch (level)
117     {
118     case 11: p = "gpgtar (GnuPG)";
119       break;
120     case 13: p = VERSION; break;
121     case 17: p = PRINTABLE_OS_NAME; break;
122     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
123
124     case 1:
125     case 40:
126       p = _("Usage: gpgtar [options] [files] [directories] (-h for help)");
127       break;
128     case 41:
129       p = _("Syntax: gpgtar [options] [files] [directories]\n"
130             "Encrypt or sign files into an archive\n");
131       break;
132
133     default: p = NULL; break;
134     }
135   return p;
136 }
137
138
139 static void
140 set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
141 {
142   enum cmd_and_opt_values cmd = *ret_cmd;
143
144   if (!cmd || cmd == new_cmd)
145     cmd = new_cmd;
146   else if (cmd == aSign && new_cmd == aEncrypt)
147     cmd = aSignEncrypt;
148   else if (cmd == aEncrypt && new_cmd == aSign)
149     cmd = aSignEncrypt;
150   else
151     {
152       log_error (_("conflicting commands\n"));
153       exit (2);
154     }
155
156   *ret_cmd = cmd;
157 }
158
159
160 \f
161 /* gpgtar main. */
162 int
163 main (int argc, char **argv)
164 {
165   ARGPARSE_ARGS pargs;
166   const char *fname;
167   int no_more_options = 0;
168   enum cmd_and_opt_values cmd = 0;
169   int skip_crypto = 0;
170   const char *files_from = NULL;
171   int null_names = 0;
172
173   assert (sizeof (struct ustar_raw_header) == 512);
174
175   gnupg_reopen_std ("gpgtar");
176   set_strusage (my_strusage);
177   log_set_prefix ("gpgtar", 1);
178
179   /* Make sure that our subsystems are ready.  */
180   i18n_init();
181   init_common_subsystems (&argc, &argv);
182
183   /* Parse the command line. */
184   pargs.argc  = &argc;
185   pargs.argv  = &argv;
186   pargs.flags = ARGPARSE_FLAG_KEEP;
187   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
188     {
189       switch (pargs.r_opt)
190         {
191         case oOutput:    opt.outfile = pargs.r.ret_str; break;
192         case oSetFilename: opt.filename = pargs.r.ret_str; break;
193         case oQuiet:     opt.quiet = 1; break;
194         case oVerbose:   opt.verbose++; break;
195         case oNoVerbose: opt.verbose = 0; break;
196         case oFilesFrom: files_from = pargs.r.ret_str; break;
197         case oNull: null_names = 1; break;
198
199         case aList:
200         case aDecrypt:
201         case aEncrypt:
202         case aSign:
203           set_cmd (&cmd, pargs.r_opt);
204           break;
205
206         case oSymmetric:
207           set_cmd (&cmd, aEncrypt);
208           opt.symmetric = 1;
209           break;
210
211         case oSkipCrypto:
212           skip_crypto = 1;
213           break;
214
215         case oOpenPGP: /* Dummy option for now.  */ break;
216         case oCMS:     /* Dummy option for now.  */ break;
217
218         default: pargs.err = 2; break;
219         }
220     }
221
222   if ((files_from && !null_names) || (!files_from && null_names))
223     log_error ("--files-from and --null may only be used in conjunction\n");
224   if (files_from && strcmp (files_from, "-"))
225     log_error ("--files-from only supports argument \"-\"\n");
226
227   if (log_get_errorcount (0))
228     exit (2);
229
230   switch (cmd)
231     {
232     case aList:
233       if (argc > 1)
234         usage (1);
235       fname = argc ? *argv : NULL;
236       if (opt.filename)
237         log_info ("note: ignoring option --set-filename\n");
238       if (files_from)
239         log_info ("note: ignoring option --files-from\n");
240       if (skip_crypto)
241         gpgtar_list (fname);
242       else
243         decrypt_and_list (fname);
244       break;
245
246     case aEncrypt:
247       if ((!argc && !null_names)
248           || (argc && null_names))
249         usage (1);
250       if (opt.filename)
251         log_info ("note: ignoring option --set-filename\n");
252       if (skip_crypto)
253         gpgtar_create (null_names? NULL :argv);
254       else
255         tar_and_encrypt (null_names? NULL : argv);
256       break;
257
258     case aDecrypt:
259       if (argc != 1)
260         usage (1);
261       if (opt.outfile)
262         log_info ("note: ignoring option --output\n");
263       if (files_from)
264         log_info ("note: ignoring option --files-from\n");
265       fname = argc ? *argv : NULL;
266       if (skip_crypto)
267         gpgtar_extract (fname);
268       else
269         decrypt_and_untar (fname);
270       break;
271
272     default:
273       log_error (_("invalid command (there is no implicit command)\n"));
274       break;
275     }
276
277   return log_get_errorcount (0)? 1:0;
278 }
279
280
281 /* Read the next record from STREAM.  RECORD is a buffer provided by
282    the caller and must be at leadt of size RECORDSIZE.  The function
283    return 0 on success and and error code on failure; a diagnostic
284    printed as well.  Note that there is no need for an EOF indicator
285    because a tarball has an explicit EOF record. */
286 gpg_error_t
287 read_record (estream_t stream, void *record)
288 {
289   gpg_error_t err;
290   size_t nread;
291
292   nread = es_fread (record, 1, RECORDSIZE, stream);
293   if (nread != RECORDSIZE)
294     {
295       err = gpg_error_from_syserror ();
296       if (es_ferror (stream))
297         log_error ("error reading `%s': %s\n",
298                    es_fname_get (stream), gpg_strerror (err));
299       else
300         log_error ("error reading `%s': premature EOF "
301                    "(size of last record: %zu)\n",
302                    es_fname_get (stream), nread);
303     }
304   else
305     err = 0;
306
307   return err;
308 }
309
310
311 /* Write the RECORD of size RECORDSIZE to STREAM.  FILENAME is the
312    name of the file used for diagnostics.  */
313 gpg_error_t
314 write_record (estream_t stream, const void *record)
315 {
316   gpg_error_t err;
317   size_t nwritten;
318
319   nwritten = es_fwrite (record, 1, RECORDSIZE, stream);
320   if (nwritten != RECORDSIZE)
321     {
322       err = gpg_error_from_syserror ();
323       log_error ("error writing `%s': %s\n",
324                  es_fname_get (stream), gpg_strerror (err));
325     }
326   else
327     err = 0;
328
329   return err;
330 }
331
332
333 /* Return true if FP is an unarmored OpenPGP message.  Note that this
334    fucntion reads a few bytes from FP but pushes them back.  */
335 #if 0
336 static int
337 openpgp_message_p (estream_t fp)
338 {
339   int ctb;
340
341   ctb = es_getc (fp);
342   if (ctb != EOF)
343     {
344       if (es_ungetc (ctb, fp))
345         log_fatal ("error ungetting first byte: %s\n",
346                    gpg_strerror (gpg_error_from_syserror ()));
347
348       if ((ctb & 0x80))
349         {
350           switch ((ctb & 0x40) ? (ctb & 0x3f) : ((ctb>>2)&0xf))
351             {
352             case PKT_MARKER:
353             case PKT_SYMKEY_ENC:
354             case PKT_ONEPASS_SIG:
355             case PKT_PUBKEY_ENC:
356             case PKT_SIGNATURE:
357             case PKT_COMMENT:
358             case PKT_OLD_COMMENT:
359             case PKT_PLAINTEXT:
360             case PKT_COMPRESSED:
361             case PKT_ENCRYPTED:
362               return 1; /* Yes, this seems to be an OpenPGP message.  */
363             default:
364               break;
365             }
366         }
367     }
368   return 0;
369 }
370 #endif
371
372
373
374 \f
375 static void
376 tar_and_encrypt (char **inpattern)
377 {
378   (void)inpattern;
379   log_error ("tar_and_encrypt has not yet been implemented\n");
380 }
381
382
383 \f
384 static void
385 decrypt_and_untar (const char *fname)
386 {
387   (void)fname;
388   log_error ("decrypt_and_untar has not yet been implemented\n");
389 }
390
391
392 \f
393 static void
394 decrypt_and_list (const char *fname)
395 {
396   (void)fname;
397   log_error ("decrypt_and_list has not yet been implemented\n");
398 }