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