991fbedf6816a6ef85c5cf6cb46745de844af9e4
[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 <assuan.h>
31 #include <errno.h>
32 #include <npth.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <assert.h>
37
38 #include "util.h"
39 #include "i18n.h"
40 #include "sysutils.h"
41 #include "../common/asshelp.h"
42 #include "../common/openpgpdefs.h"
43 #include "../common/init.h"
44
45 #include "gpgtar.h"
46
47
48 /* Constants to identify the commands and options. */
49 enum cmd_and_opt_values
50   {
51     aNull = 0,
52     aEncrypt    = 'e',
53     aDecrypt    = 'd',
54     aSign       = 's',
55     aList       = 't',
56
57     oSymmetric  = 'c',
58     oRecipient  = 'r',
59     oUser       = 'u',
60     oOutput     = 'o',
61     oDirectory  = 'C',
62     oQuiet      = 'q',
63     oVerbose    = 'v',
64     oFilesFrom  = 'T',
65     oNoVerbose  = 500,
66
67     aSignEncrypt,
68     oGpgProgram,
69     oSkipCrypto,
70     oOpenPGP,
71     oCMS,
72     oSetFilename,
73     oNull
74   };
75
76
77 /* The list of commands and options. */
78 static ARGPARSE_OPTS opts[] = {
79   ARGPARSE_group (300, N_("@Commands:\n ")),
80
81   ARGPARSE_c (aEncrypt,   "encrypt", N_("create an archive")),
82   ARGPARSE_c (aDecrypt,   "decrypt", N_("extract an archive")),
83   ARGPARSE_c (aSign,      "sign",    N_("create a signed archive")),
84   ARGPARSE_c (aList,      "list-archive", N_("list an archive")),
85
86   ARGPARSE_group (301, N_("@\nOptions:\n ")),
87
88   ARGPARSE_s_n (oSymmetric, "symmetric", N_("use symmetric encryption")),
89   ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
90   ARGPARSE_s_s (oUser, "local-user",
91                 N_("|USER-ID|use USER-ID to sign or decrypt")),
92   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
93   ARGPARSE_s_s (oDirectory, "directory",
94                 N_("|DIRECTORY|extract files into DIRECTORY")),
95   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
96   ARGPARSE_s_n (oQuiet, "quiet",  N_("be somewhat more quiet")),
97   ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
98   ARGPARSE_s_n (oSkipCrypto, "skip-crypto", N_("skip the crypto processing")),
99   ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
100   ARGPARSE_s_s (oFilesFrom, "files-from",
101                 N_("|FILE|get names to create from FILE")),
102   ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")),
103   ARGPARSE_s_n (oOpenPGP, "openpgp", "@"),
104   ARGPARSE_s_n (oCMS, "cms", "@"),
105
106   ARGPARSE_end ()
107 };
108
109
110 \f
111 /* Print usage information and and provide strings for help. */
112 static const char *
113 my_strusage( int level )
114 {
115   const char *p;
116
117   switch (level)
118     {
119     case 11: p = "@GPGTAR@ (@GNUPG@)";
120       break;
121     case 13: p = VERSION; break;
122     case 17: p = PRINTABLE_OS_NAME; break;
123     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
124
125     case 1:
126     case 40:
127       p = _("Usage: gpgtar [options] [files] [directories] (-h for help)");
128       break;
129     case 41:
130       p = _("Syntax: gpgtar [options] [files] [directories]\n"
131             "Encrypt or sign files into an archive\n");
132       break;
133
134     default: p = NULL; break;
135     }
136   return p;
137 }
138
139
140 static void
141 set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
142 {
143   enum cmd_and_opt_values cmd = *ret_cmd;
144
145   if (!cmd || cmd == new_cmd)
146     cmd = new_cmd;
147   else if (cmd == aSign && new_cmd == aEncrypt)
148     cmd = aSignEncrypt;
149   else if (cmd == aEncrypt && new_cmd == aSign)
150     cmd = aSignEncrypt;
151   else
152     {
153       log_error (_("conflicting commands\n"));
154       exit (2);
155     }
156
157   *ret_cmd = cmd;
158 }
159
160 ASSUAN_SYSTEM_NPTH_IMPL;
161
162 \f
163 /* gpgtar main. */
164 int
165 main (int argc, char **argv)
166 {
167   gpg_error_t err;
168   ARGPARSE_ARGS pargs;
169   const char *fname;
170   int no_more_options = 0;
171   enum cmd_and_opt_values cmd = 0;
172   int skip_crypto = 0;
173   const char *files_from = NULL;
174   int null_names = 0;
175
176   assert (sizeof (struct ustar_raw_header) == 512);
177
178   gnupg_reopen_std (GPGTAR_NAME);
179   set_strusage (my_strusage);
180   log_set_prefix (GPGTAR_NAME, 1);
181
182   /* Make sure that our subsystems are ready.  */
183   i18n_init();
184   init_common_subsystems (&argc, &argv);
185   npth_init ();
186   assuan_set_assuan_log_prefix (log_get_prefix (NULL));
187   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
188   assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
189   assuan_sock_init ();
190
191   /* Parse the command line. */
192   pargs.argc  = &argc;
193   pargs.argv  = &argv;
194   pargs.flags = ARGPARSE_FLAG_KEEP;
195   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
196     {
197       switch (pargs.r_opt)
198         {
199         case oOutput:    opt.outfile = pargs.r.ret_str; break;
200         case oDirectory: opt.directory = pargs.r.ret_str; break;
201         case oSetFilename: opt.filename = pargs.r.ret_str; break;
202         case oQuiet:     opt.quiet = 1; break;
203         case oVerbose:   opt.verbose++; break;
204         case oNoVerbose: opt.verbose = 0; break;
205         case oFilesFrom: files_from = pargs.r.ret_str; break;
206         case oNull: null_names = 1; break;
207
208         case aList:
209         case aDecrypt:
210         case aEncrypt:
211         case aSign:
212           set_cmd (&cmd, pargs.r_opt);
213           break;
214
215         case oRecipient:
216           add_to_strlist (&opt.recipients, pargs.r.ret_str);
217           break;
218
219         case oUser:
220           log_info ("note: ignoring option --user\n");
221           opt.user = pargs.r.ret_str;
222           break;
223
224         case oSymmetric:
225           log_info ("note: ignoring option --symmetric\n");
226           set_cmd (&cmd, aEncrypt);
227           opt.symmetric = 1;
228           break;
229
230         case oGpgProgram:
231           opt.gpg_program = pargs.r.ret_str;
232           break;
233
234         case oSkipCrypto:
235           skip_crypto = 1;
236           break;
237
238         case oOpenPGP: /* Dummy option for now.  */ break;
239         case oCMS:     /* Dummy option for now.  */ break;
240
241         default: pargs.err = 2; break;
242         }
243     }
244
245   if ((files_from && !null_names) || (!files_from && null_names))
246     log_error ("--files-from and --null may only be used in conjunction\n");
247   if (files_from && strcmp (files_from, "-"))
248     log_error ("--files-from only supports argument \"-\"\n");
249
250   if (log_get_errorcount (0))
251     exit (2);
252
253   /* Print a warning if an argument looks like an option.  */
254   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
255     {
256       int i;
257
258       for (i=0; i < argc; i++)
259         if (argv[i][0] == '-' && argv[i][1] == '-')
260           log_info (_("NOTE: '%s' is not considered an option\n"), argv[i]);
261     }
262
263   if (opt.verbose > 1)
264     opt.debug_level = 1024;
265   setup_libassuan_logging (&opt.debug_level);
266
267   switch (cmd)
268     {
269     case aList:
270       if (argc > 1)
271         usage (1);
272       fname = argc ? *argv : NULL;
273       if (opt.filename)
274         log_info ("note: ignoring option --set-filename\n");
275       if (files_from)
276         log_info ("note: ignoring option --files-from\n");
277       err = gpgtar_list (fname, !skip_crypto);
278       if (err && log_get_errorcount (0) == 0)
279         log_error ("listing archive failed: %s\n", gpg_strerror (err));
280       break;
281
282     case aEncrypt:
283       if ((!argc && !null_names)
284           || (argc && null_names))
285         usage (1);
286       if (opt.filename)
287         log_info ("note: ignoring option --set-filename\n");
288       err = gpgtar_create (null_names? NULL :argv, !skip_crypto);
289       if (err && log_get_errorcount (0) == 0)
290         log_error ("creating archive failed: %s\n", gpg_strerror (err));
291       break;
292
293     case aDecrypt:
294       if (argc != 1)
295         usage (1);
296       if (opt.outfile)
297         log_info ("note: ignoring option --output\n");
298       if (files_from)
299         log_info ("note: ignoring option --files-from\n");
300       fname = argc ? *argv : NULL;
301       err = gpgtar_extract (fname, !skip_crypto);
302       if (err && log_get_errorcount (0) == 0)
303         log_error ("extracting archive failed: %s\n", gpg_strerror (err));
304       break;
305
306     default:
307       log_error (_("invalid command (there is no implicit command)\n"));
308       break;
309     }
310
311   return log_get_errorcount (0)? 1:0;
312 }
313
314
315 /* Read the next record from STREAM.  RECORD is a buffer provided by
316    the caller and must be at leadt of size RECORDSIZE.  The function
317    return 0 on success and and error code on failure; a diagnostic
318    printed as well.  Note that there is no need for an EOF indicator
319    because a tarball has an explicit EOF record. */
320 gpg_error_t
321 read_record (estream_t stream, void *record)
322 {
323   gpg_error_t err;
324   size_t nread;
325
326   nread = es_fread (record, 1, RECORDSIZE, stream);
327   if (nread != RECORDSIZE)
328     {
329       err = gpg_error_from_syserror ();
330       if (es_ferror (stream))
331         log_error ("error reading '%s': %s\n",
332                    es_fname_get (stream), gpg_strerror (err));
333       else
334         log_error ("error reading '%s': premature EOF "
335                    "(size of last record: %zu)\n",
336                    es_fname_get (stream), nread);
337     }
338   else
339     err = 0;
340
341   return err;
342 }
343
344
345 /* Write the RECORD of size RECORDSIZE to STREAM.  FILENAME is the
346    name of the file used for diagnostics.  */
347 gpg_error_t
348 write_record (estream_t stream, const void *record)
349 {
350   gpg_error_t err;
351   size_t nwritten;
352
353   nwritten = es_fwrite (record, 1, RECORDSIZE, stream);
354   if (nwritten != RECORDSIZE)
355     {
356       err = gpg_error_from_syserror ();
357       log_error ("error writing '%s': %s\n",
358                  es_fname_get (stream), gpg_strerror (err));
359     }
360   else
361     err = 0;
362
363   return err;
364 }
365
366
367 /* Return true if FP is an unarmored OpenPGP message.  Note that this
368    function reads a few bytes from FP but pushes them back.  */
369 #if 0
370 static int
371 openpgp_message_p (estream_t fp)
372 {
373   int ctb;
374
375   ctb = es_getc (fp);
376   if (ctb != EOF)
377     {
378       if (es_ungetc (ctb, fp))
379         log_fatal ("error ungetting first byte: %s\n",
380                    gpg_strerror (gpg_error_from_syserror ()));
381
382       if ((ctb & 0x80))
383         {
384           switch ((ctb & 0x40) ? (ctb & 0x3f) : ((ctb>>2)&0xf))
385             {
386             case PKT_MARKER:
387             case PKT_SYMKEY_ENC:
388             case PKT_ONEPASS_SIG:
389             case PKT_PUBKEY_ENC:
390             case PKT_SIGNATURE:
391             case PKT_COMMENT:
392             case PKT_OLD_COMMENT:
393             case PKT_PLAINTEXT:
394             case PKT_COMPRESSED:
395             case PKT_ENCRYPTED:
396               return 1; /* Yes, this seems to be an OpenPGP message.  */
397             default:
398               break;
399             }
400         }
401     }
402   return 0;
403 }
404 #endif