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