1 /* gpgtar-create.c - Create a TAR archive
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 <https://www.gnu.org/licenses/>.
18  */
19 
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <dirent.h>
28 #ifdef HAVE_W32_SYSTEM
29 # define WIN32_LEAN_AND_MEAN
30 # include <windows.h>
31 #else /*!HAVE_W32_SYSTEM*/
32 # include <unistd.h>
33 # include <pwd.h>
34 # include <grp.h>
35 #endif /*!HAVE_W32_SYSTEM*/
36 #include <assert.h>
37 
38 #include "../common/i18n.h"
39 #include "../common/exectool.h"
40 #include "../common/sysutils.h"
41 #include "../common/ccparray.h"
42 #include "gpgtar.h"
43 
44 #ifndef HAVE_LSTAT
45 #define lstat(a,b) gnupg_stat ((a), (b))
46 #endif
47 
48 
49 /* Object to control the file scanning.  */
50 struct scanctrl_s;
51 typedef struct scanctrl_s *scanctrl_t;
52 struct scanctrl_s
53 {
54   tar_header_t flist;
55   tar_header_t *flist_tail;
56   int nestlevel;
57 };
58 
59 
60 
61 /* On Windows convert name to UTF8 and return it; caller must release
62  * the result.  On Unix or if ALREADY_UTF8 is set, this function is a
63  * mere xtrystrcopy.  On failure NULL is returned and ERRNO set. */
64 static char *
name_to_utf8(const char * name,int already_utf8)65 name_to_utf8 (const char *name, int already_utf8)
66 {
67 #ifdef HAVE_W32_SYSTEM
68   wchar_t *wstring;
69   char *result;
70 
71   if (already_utf8)
72     result = xtrystrdup (name);
73   else
74     {
75       wstring = native_to_wchar (name);
76       if (!wstring)
77         return NULL;
78       result = wchar_to_utf8 (wstring);
79       xfree (wstring);
80     }
81   return result;
82 
83 #else /*!HAVE_W32_SYSTEM */
84 
85   (void)already_utf8;
86   return xtrystrdup (name);
87 
88 #endif /*!HAVE_W32_SYSTEM */
89 }
90 
91 
92 
93 
94 /* Given a fresh header object HDR with only the name field set, try
95    to gather all available info.  This is the W32 version.  */
96 #ifdef HAVE_W32_SYSTEM
97 static gpg_error_t
fillup_entry_w32(tar_header_t hdr)98 fillup_entry_w32 (tar_header_t hdr)
99 {
100   char *p;
101   wchar_t *wfname;
102   WIN32_FILE_ATTRIBUTE_DATA fad;
103   DWORD attr;
104 
105   for (p=hdr->name; *p; p++)
106     if (*p == '/')
107       *p = '\\';
108   wfname = utf8_to_wchar (hdr->name);
109   for (p=hdr->name; *p; p++)
110     if (*p == '\\')
111       *p = '/';
112   if (!wfname)
113     {
114       log_error ("error converting '%s': %s\n", hdr->name, w32_strerror (-1));
115       return gpg_error_from_syserror ();
116     }
117   if (!GetFileAttributesExW (wfname, GetFileExInfoStandard, &fad))
118     {
119       log_error ("error stat-ing '%s': %s\n", hdr->name, w32_strerror (-1));
120       xfree (wfname);
121       return gpg_error_from_syserror ();
122     }
123   xfree (wfname);
124 
125   attr = fad.dwFileAttributes;
126 
127   if ((attr & FILE_ATTRIBUTE_NORMAL))
128     hdr->typeflag = TF_REGULAR;
129   else if ((attr & FILE_ATTRIBUTE_DIRECTORY))
130     hdr->typeflag = TF_DIRECTORY;
131   else if ((attr & FILE_ATTRIBUTE_DEVICE))
132     hdr->typeflag = TF_NOTSUP;
133   else if ((attr & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_TEMPORARY)))
134     hdr->typeflag = TF_NOTSUP;
135   else
136     hdr->typeflag = TF_REGULAR;
137 
138   /* Map some attributes to  USTAR defined mode bits.  */
139   hdr->mode = 0640;      /* User may read and write, group only read.  */
140   if ((attr & FILE_ATTRIBUTE_DIRECTORY))
141     hdr->mode |= 0110;   /* Dirs are user and group executable.  */
142   if ((attr & FILE_ATTRIBUTE_READONLY))
143     hdr->mode &= ~0200;  /* Clear the user write bit.  */
144   if ((attr & FILE_ATTRIBUTE_HIDDEN))
145     hdr->mode &= ~0707;  /* Clear all user and other bits.  */
146   if ((attr & FILE_ATTRIBUTE_SYSTEM))
147     hdr->mode |= 0004;   /* Make it readable by other.  */
148 
149   /* Only set the size for a regular file.  */
150   if (hdr->typeflag == TF_REGULAR)
151     hdr->size = (fad.nFileSizeHigh * ((unsigned long long)MAXDWORD+1)
152                  + fad.nFileSizeLow);
153 
154   hdr->mtime = (((unsigned long long)fad.ftLastWriteTime.dwHighDateTime << 32)
155                 | fad.ftLastWriteTime.dwLowDateTime);
156   if (!hdr->mtime)
157     hdr->mtime = (((unsigned long long)fad.ftCreationTime.dwHighDateTime << 32)
158                   | fad.ftCreationTime.dwLowDateTime);
159   hdr->mtime -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01.  */
160   hdr->mtime /= 10000000;  /* Convert from 0.1us to seconds. */
161 
162   return 0;
163 }
164 #endif /*HAVE_W32_SYSTEM*/
165 
166 
167 /* Given a fresh header object HDR with only the name field set, try
168    to gather all available info.  This is the POSIX version.  */
169 #ifndef HAVE_W32_SYSTEM
170 static gpg_error_t
fillup_entry_posix(tar_header_t hdr)171 fillup_entry_posix (tar_header_t hdr)
172 {
173   gpg_error_t err;
174   struct stat sbuf;
175 
176   if (lstat (hdr->name, &sbuf))
177     {
178       err = gpg_error_from_syserror ();
179       log_error ("error stat-ing '%s': %s\n", hdr->name, gpg_strerror (err));
180       return err;
181     }
182 
183   if (S_ISREG (sbuf.st_mode))
184     hdr->typeflag = TF_REGULAR;
185   else if (S_ISDIR (sbuf.st_mode))
186     hdr->typeflag = TF_DIRECTORY;
187   else if (S_ISCHR (sbuf.st_mode))
188     hdr->typeflag = TF_CHARDEV;
189   else if (S_ISBLK (sbuf.st_mode))
190     hdr->typeflag = TF_BLOCKDEV;
191   else if (S_ISFIFO (sbuf.st_mode))
192     hdr->typeflag = TF_FIFO;
193   else if (S_ISLNK (sbuf.st_mode))
194     hdr->typeflag = TF_SYMLINK;
195   else
196     hdr->typeflag = TF_NOTSUP;
197 
198   /* FIXME: Save DEV and INO? */
199 
200   /* Set the USTAR defined mode bits using the system macros.  */
201   if (sbuf.st_mode & S_IRUSR)
202     hdr->mode |= 0400;
203   if (sbuf.st_mode & S_IWUSR)
204     hdr->mode |= 0200;
205   if (sbuf.st_mode & S_IXUSR)
206     hdr->mode |= 0100;
207   if (sbuf.st_mode & S_IRGRP)
208     hdr->mode |= 0040;
209   if (sbuf.st_mode & S_IWGRP)
210     hdr->mode |= 0020;
211   if (sbuf.st_mode & S_IXGRP)
212     hdr->mode |= 0010;
213   if (sbuf.st_mode & S_IROTH)
214     hdr->mode |= 0004;
215   if (sbuf.st_mode & S_IWOTH)
216     hdr->mode |= 0002;
217   if (sbuf.st_mode & S_IXOTH)
218     hdr->mode |= 0001;
219 #ifdef S_IXUID
220   if (sbuf.st_mode & S_IXUID)
221     hdr->mode |= 04000;
222 #endif
223 #ifdef S_IXGID
224   if (sbuf.st_mode & S_IXGID)
225     hdr->mode |= 02000;
226 #endif
227 #ifdef S_ISVTX
228   if (sbuf.st_mode & S_ISVTX)
229     hdr->mode |= 01000;
230 #endif
231 
232   hdr->nlink = sbuf.st_nlink;
233 
234   hdr->uid = sbuf.st_uid;
235   hdr->gid = sbuf.st_gid;
236 
237   /* Only set the size for a regular file.  */
238   if (hdr->typeflag == TF_REGULAR)
239     hdr->size = sbuf.st_size;
240 
241   hdr->mtime = sbuf.st_mtime;
242 
243   return 0;
244 }
245 #endif /*!HAVE_W32_SYSTEM*/
246 
247 
248 /* Add a new entry.  The name of a directory entry is ENTRYNAME; if
249    that is NULL, DNAME is the name of the directory itself.  Under
250    Windows ENTRYNAME shall have backslashes replaced by standard
251    slashes.  */
252 static gpg_error_t
add_entry(const char * dname,const char * entryname,scanctrl_t scanctrl)253 add_entry (const char *dname, const char *entryname, scanctrl_t scanctrl)
254 {
255   gpg_error_t err;
256   tar_header_t hdr;
257   char *p;
258   size_t dnamelen = strlen (dname);
259 
260   log_assert (dnamelen);
261 
262   hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1
263                     + (entryname? strlen (entryname) : 0) + 1);
264   if (!hdr)
265     return gpg_error_from_syserror ();
266 
267   p = stpcpy (hdr->name, dname);
268   if (entryname)
269     {
270       if (dname[dnamelen-1] != '/')
271         *p++ = '/';
272       strcpy (p, entryname);
273     }
274   else
275     {
276       if (hdr->name[dnamelen-1] == '/')
277         hdr->name[dnamelen-1] = 0;
278     }
279 #ifdef HAVE_DOSISH_SYSTEM
280   err = fillup_entry_w32 (hdr);
281 #else
282   err = fillup_entry_posix (hdr);
283 #endif
284   if (err)
285     xfree (hdr);
286   else
287     {
288       if (opt.verbose)
289         gpgtar_print_header (hdr, log_get_stream ());
290       *scanctrl->flist_tail = hdr;
291       scanctrl->flist_tail = &hdr->next;
292     }
293 
294   return 0;
295 }
296 
297 
298 static gpg_error_t
scan_directory(const char * dname,scanctrl_t scanctrl)299 scan_directory (const char *dname, scanctrl_t scanctrl)
300 {
301   gpg_error_t err = 0;
302 
303 #ifdef HAVE_W32_SYSTEM
304   /* Note that we introduced gnupg_opendir only after we had deployed
305    * this code and thus we don't change it for now.  */
306   WIN32_FIND_DATAW fi;
307   HANDLE hd = INVALID_HANDLE_VALUE;
308   char *p;
309 
310   if (!*dname)
311     return 0;  /* An empty directory name has no entries.  */
312 
313   {
314     char *fname;
315     wchar_t *wfname;
316 
317     fname = xtrymalloc (strlen (dname) + 2 + 2 + 1);
318     if (!fname)
319       {
320         err = gpg_error_from_syserror ();
321         goto leave;
322       }
323     if (!strcmp (dname, "/"))
324       strcpy (fname, "/*"); /* Trailing slash is not allowed.  */
325     else if (!strcmp (dname, "."))
326       strcpy (fname, "*");
327     else if (*dname && dname[strlen (dname)-1] == '/')
328       strcpy (stpcpy (fname, dname), "*");
329     else if (*dname && dname[strlen (dname)-1] != '*')
330       strcpy (stpcpy (fname, dname), "/*");
331     else
332       strcpy (fname, dname);
333 
334     for (p=fname; *p; p++)
335       if (*p == '/')
336         *p = '\\';
337     wfname = utf8_to_wchar (fname);
338     xfree (fname);
339     if (!wfname)
340       {
341         err = gpg_error_from_syserror ();
342         log_error (_("error reading directory '%s': %s\n"),
343                    dname, gpg_strerror (err));
344         goto leave;
345       }
346     hd = FindFirstFileW (wfname, &fi);
347     if (hd == INVALID_HANDLE_VALUE)
348       {
349         err = gpg_error_from_syserror ();
350         log_error (_("error reading directory '%s': %s\n"),
351                    dname, w32_strerror (-1));
352         xfree (wfname);
353         goto leave;
354       }
355     xfree (wfname);
356   }
357 
358   do
359     {
360       char *fname = wchar_to_utf8 (fi.cFileName);
361       if (!fname)
362         {
363           err = gpg_error_from_syserror ();
364           log_error ("error converting filename: %s\n", w32_strerror (-1));
365           break;
366         }
367       for (p=fname; *p; p++)
368         if (*p == '\\')
369           *p = '/';
370       if (!strcmp (fname, "." ) || !strcmp (fname, ".."))
371         err = 0; /* Skip self and parent dir entry.  */
372       else if (!strncmp (dname, "./", 2) && dname[2])
373         err = add_entry (dname+2, fname, scanctrl);
374       else
375         err = add_entry (dname, fname, scanctrl);
376       xfree (fname);
377     }
378   while (!err && FindNextFileW (hd, &fi));
379   if (err)
380     ;
381   else if (GetLastError () == ERROR_NO_MORE_FILES)
382     err = 0;
383   else
384     {
385       err = gpg_error_from_syserror ();
386       log_error (_("error reading directory '%s': %s\n"),
387                  dname, w32_strerror (-1));
388     }
389 
390  leave:
391   if (hd != INVALID_HANDLE_VALUE)
392     FindClose (hd);
393 
394 #else /*!HAVE_W32_SYSTEM*/
395   DIR *dir;
396   struct dirent *de;
397 
398   if (!*dname)
399     return 0;  /* An empty directory name has no entries.  */
400 
401   dir = opendir (dname);
402   if (!dir)
403     {
404       err = gpg_error_from_syserror ();
405       log_error (_("error reading directory '%s': %s\n"),
406                  dname, gpg_strerror (err));
407       return err;
408     }
409 
410   while ((de = readdir (dir)))
411     {
412       if (!strcmp (de->d_name, "." ) || !strcmp (de->d_name, ".."))
413         continue; /* Skip self and parent dir entry.  */
414 
415       err = add_entry (dname, de->d_name, scanctrl);
416       if (err)
417         goto leave;
418      }
419 
420  leave:
421   closedir (dir);
422 #endif /*!HAVE_W32_SYSTEM*/
423   return err;
424 }
425 
426 
427 static gpg_error_t
scan_recursive(const char * dname,scanctrl_t scanctrl)428 scan_recursive (const char *dname, scanctrl_t scanctrl)
429 {
430   gpg_error_t err = 0;
431   tar_header_t hdr, *start_tail, *stop_tail;
432 
433   if (scanctrl->nestlevel > 200)
434     {
435       log_error ("directories too deeply nested\n");
436       return gpg_error (GPG_ERR_RESOURCE_LIMIT);
437     }
438   scanctrl->nestlevel++;
439 
440   assert (scanctrl->flist_tail);
441   start_tail = scanctrl->flist_tail;
442   scan_directory (dname, scanctrl);
443   stop_tail = scanctrl->flist_tail;
444   hdr = *start_tail;
445   for (; hdr && hdr != *stop_tail; hdr = hdr->next)
446     if (hdr->typeflag == TF_DIRECTORY)
447       {
448         if (opt.verbose > 1)
449           log_info ("scanning directory '%s'\n", hdr->name);
450         scan_recursive (hdr->name, scanctrl);
451       }
452 
453   scanctrl->nestlevel--;
454   return err;
455 }
456 
457 
458 /* Returns true if PATTERN is acceptable.  */
459 static int
pattern_valid_p(const char * pattern)460 pattern_valid_p (const char *pattern)
461 {
462   if (!*pattern)
463     return 0;
464   if (*pattern == '.' && pattern[1] == '.')
465     return 0;
466   if (*pattern == '/'
467 #ifdef HAVE_DOSISH_SYSTEM
468       || *pattern == '\\'
469 #endif
470       )
471     return 0; /* Absolute filenames are not supported.  */
472 #ifdef HAVE_DRIVE_LETTERS
473   if (((*pattern >= 'a' && *pattern <= 'z')
474        || (*pattern >= 'A' && *pattern <= 'Z'))
475       && pattern[1] == ':')
476     return 0; /* Drive letter are not allowed either.  */
477 #endif /*HAVE_DRIVE_LETTERS*/
478 
479   return 1; /* Okay.  */
480 }
481 
482 
483 
484 static void
store_xoctal(char * buffer,size_t length,unsigned long long value)485 store_xoctal (char *buffer, size_t length, unsigned long long value)
486 {
487   char *p, *pend;
488   size_t n;
489   unsigned long long v;
490 
491   assert (length > 1);
492 
493   v = value;
494   n = length;
495   p = pend = buffer + length;
496   *--p = 0; /* Nul byte.  */
497   n--;
498   do
499     {
500       *--p = '0' + (v % 8);
501       v /= 8;
502       n--;
503     }
504   while (v && n);
505   if (!v)
506     {
507       /* Pad.  */
508       for ( ; n; n--)
509         *--p = '0';
510     }
511   else /* Does not fit into the field.  Store as binary number.  */
512     {
513       v = value;
514       n = length;
515       p = pend = buffer + length;
516       do
517         {
518           *--p = v;
519           v /= 256;
520           n--;
521         }
522       while (v && n);
523       if (!v)
524         {
525           /* Pad.  */
526           for ( ; n; n--)
527             *--p = 0;
528           if (*p & 0x80)
529             BUG ();
530           *p |= 0x80; /* Set binary flag.  */
531         }
532       else
533         BUG ();
534     }
535 }
536 
537 
538 static void
store_uname(char * buffer,size_t length,unsigned long uid)539 store_uname (char *buffer, size_t length, unsigned long uid)
540 {
541   static int initialized;
542   static unsigned long lastuid;
543   static char lastuname[32];
544 
545   if (!initialized || uid != lastuid)
546     {
547 #ifdef HAVE_W32_SYSTEM
548       mem2str (lastuname, uid? "user":"root", sizeof lastuname);
549 #else
550       struct passwd *pw = getpwuid (uid);
551 
552       lastuid = uid;
553       initialized = 1;
554       if (pw)
555         mem2str (lastuname, pw->pw_name, sizeof lastuname);
556       else
557         {
558           log_info ("failed to get name for uid %lu\n", uid);
559           *lastuname = 0;
560         }
561 #endif
562     }
563   mem2str (buffer, lastuname, length);
564 }
565 
566 
567 static void
store_gname(char * buffer,size_t length,unsigned long gid)568 store_gname (char *buffer, size_t length, unsigned long gid)
569 {
570   static int initialized;
571   static unsigned long lastgid;
572   static char lastgname[32];
573 
574   if (!initialized || gid != lastgid)
575     {
576 #ifdef HAVE_W32_SYSTEM
577       mem2str (lastgname, gid? "users":"root", sizeof lastgname);
578 #else
579       struct group *gr = getgrgid (gid);
580 
581       lastgid = gid;
582       initialized = 1;
583       if (gr)
584         mem2str (lastgname, gr->gr_name, sizeof lastgname);
585       else
586         {
587           log_info ("failed to get name for gid %lu\n", gid);
588           *lastgname = 0;
589         }
590 #endif
591     }
592   mem2str (buffer, lastgname, length);
593 }
594 
595 
596 static gpg_error_t
build_header(void * record,tar_header_t hdr)597 build_header (void *record, tar_header_t hdr)
598 {
599   gpg_error_t err;
600   struct ustar_raw_header *raw = record;
601   size_t namelen, n;
602   unsigned long chksum;
603   unsigned char *p;
604 
605   memset (record, 0, RECORDSIZE);
606 
607   /* Store name and prefix.  */
608   namelen = strlen (hdr->name);
609   if (namelen < sizeof raw->name)
610     memcpy (raw->name, hdr->name, namelen);
611   else
612     {
613       n = (namelen < sizeof raw->prefix)? namelen : sizeof raw->prefix;
614       for (n--; n ; n--)
615         if (hdr->name[n] == '/')
616           break;
617       if (namelen - n < sizeof raw->name)
618         {
619           /* Note that the N is < sizeof prefix and that the
620              delimiting slash is not stored.  */
621           memcpy (raw->prefix, hdr->name, n);
622           memcpy (raw->name, hdr->name+n+1, namelen - n);
623         }
624       else
625         {
626           err = gpg_error (GPG_ERR_TOO_LARGE);
627           log_error ("error storing file '%s': %s\n",
628                      hdr->name, gpg_strerror (err));
629           return err;
630         }
631     }
632 
633   store_xoctal (raw->mode,  sizeof raw->mode,  hdr->mode);
634   store_xoctal (raw->uid,   sizeof raw->uid,   hdr->uid);
635   store_xoctal (raw->gid,   sizeof raw->gid,   hdr->gid);
636   store_xoctal (raw->size,  sizeof raw->size,  hdr->size);
637   store_xoctal (raw->mtime, sizeof raw->mtime, hdr->mtime);
638 
639   switch (hdr->typeflag)
640     {
641     case TF_REGULAR:   raw->typeflag[0] = '0'; break;
642     case TF_HARDLINK:  raw->typeflag[0] = '1'; break;
643     case TF_SYMLINK:   raw->typeflag[0] = '2'; break;
644     case TF_CHARDEV:   raw->typeflag[0] = '3'; break;
645     case TF_BLOCKDEV:  raw->typeflag[0] = '4'; break;
646     case TF_DIRECTORY: raw->typeflag[0] = '5'; break;
647     case TF_FIFO:      raw->typeflag[0] = '6'; break;
648     default: return gpg_error (GPG_ERR_NOT_SUPPORTED);
649     }
650 
651   memcpy (raw->magic, "ustar", 6);
652   raw->version[0] = '0';
653   raw->version[1] = '0';
654 
655   store_uname (raw->uname, sizeof raw->uname, hdr->uid);
656   store_gname (raw->gname, sizeof raw->gname, hdr->gid);
657 
658 #ifndef HAVE_W32_SYSTEM
659   if (hdr->typeflag == TF_SYMLINK)
660     {
661       int nread;
662 
663       nread = readlink (hdr->name, raw->linkname, sizeof raw->linkname -1);
664       if (nread < 0)
665         {
666           err = gpg_error_from_syserror ();
667           log_error ("error reading symlink '%s': %s\n",
668                      hdr->name, gpg_strerror (err));
669           return err;
670         }
671       raw->linkname[nread] = 0;
672     }
673 #endif /*HAVE_W32_SYSTEM*/
674 
675   /* Compute the checksum.  */
676   memset (raw->checksum, ' ', sizeof raw->checksum);
677   chksum = 0;
678   p = record;
679   for (n=0; n < RECORDSIZE; n++)
680     chksum += *p++;
681   store_xoctal (raw->checksum, sizeof raw->checksum - 1, chksum);
682   raw->checksum[7] = ' ';
683 
684   return 0;
685 }
686 
687 
688 static gpg_error_t
write_file(estream_t stream,tar_header_t hdr)689 write_file (estream_t stream, tar_header_t hdr)
690 {
691   gpg_error_t err;
692   char record[RECORDSIZE];
693   estream_t infp;
694   size_t nread, nbytes;
695   int any;
696 
697   err = build_header (record, hdr);
698   if (err)
699     {
700       if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
701         {
702           log_info ("skipping unsupported file '%s'\n", hdr->name);
703           err = 0;
704         }
705       return err;
706     }
707 
708   if (hdr->typeflag == TF_REGULAR)
709     {
710       infp = es_fopen (hdr->name, "rb");
711       if (!infp)
712         {
713           err = gpg_error_from_syserror ();
714           log_error ("can't open '%s': %s - skipped\n",
715                      hdr->name, gpg_strerror (err));
716           return err;
717         }
718     }
719   else
720     infp = NULL;
721 
722   err = write_record (stream, record);
723   if (err)
724     goto leave;
725 
726   if (hdr->typeflag == TF_REGULAR)
727     {
728       hdr->nrecords = (hdr->size + RECORDSIZE-1)/RECORDSIZE;
729       any = 0;
730       while (hdr->nrecords--)
731         {
732           nbytes = hdr->nrecords? RECORDSIZE : (hdr->size % RECORDSIZE);
733           if (!nbytes)
734             nbytes = RECORDSIZE;
735           nread = es_fread (record, 1, nbytes, infp);
736           if (nread != nbytes)
737             {
738               err = gpg_error_from_syserror ();
739               log_error ("error reading file '%s': %s%s\n",
740                          hdr->name, gpg_strerror (err),
741                          any? " (file shrunk?)":"");
742               goto leave;
743             }
744           any = 1;
745           err = write_record (stream, record);
746           if (err)
747             goto leave;
748         }
749       nread = es_fread (record, 1, 1, infp);
750       if (nread)
751         log_info ("note: file '%s' has grown\n", hdr->name);
752     }
753 
754  leave:
755   if (err)
756     es_fclose (infp);
757   else if ((err = es_fclose (infp)))
758     log_error ("error closing file '%s': %s\n", hdr->name, gpg_strerror (err));
759 
760   return err;
761 }
762 
763 
764 static gpg_error_t
write_eof_mark(estream_t stream)765 write_eof_mark (estream_t stream)
766 {
767   gpg_error_t err;
768   char record[RECORDSIZE];
769 
770   memset (record, 0, sizeof record);
771   err = write_record (stream, record);
772   if (!err)
773     err = write_record (stream, record);
774   return err;
775 }
776 
777 
778 
779 /* Create a new tarball using the names in the array INPATTERN.  If
780    INPATTERN is NULL take the pattern as null terminated strings from
781    stdin or from the file specified by FILES_FROM.  If NULL_NAMES is
782    set the filenames in such a file are delimited by a binary Nul and
783    not by a LF.  */
784 gpg_error_t
gpgtar_create(char ** inpattern,const char * files_from,int null_names,int encrypt,int sign)785 gpgtar_create (char **inpattern, const char *files_from, int null_names,
786                int encrypt, int sign)
787 {
788   gpg_error_t err = 0;
789   struct scanctrl_s scanctrl_buffer;
790   scanctrl_t scanctrl = &scanctrl_buffer;
791   tar_header_t hdr, *start_tail;
792   estream_t files_from_stream = NULL;
793   estream_t outstream = NULL;
794   estream_t cipher_stream = NULL;
795   int eof_seen = 0;
796 
797   memset (scanctrl, 0, sizeof *scanctrl);
798   scanctrl->flist_tail = &scanctrl->flist;
799 
800   if (!inpattern)
801     {
802       if (!files_from || !strcmp (files_from, "-"))
803         {
804           files_from = "-";
805           files_from_stream = es_stdin;
806           if (null_names)
807             es_set_binary (es_stdin);
808         }
809       else if (!(files_from_stream=es_fopen (files_from, null_names? "rb":"r")))
810         {
811           err = gpg_error_from_syserror ();
812           log_error ("error opening '%s': %s\n",
813                      files_from, gpg_strerror (err));
814           return err;
815         }
816     }
817 
818 
819   if (opt.directory && gnupg_chdir (opt.directory))
820     {
821       err = gpg_error_from_syserror ();
822       log_error ("chdir to '%s' failed: %s\n",
823                  opt.directory, gpg_strerror (err));
824       return err;
825     }
826 
827   while (!eof_seen)
828     {
829       char *pat, *p;
830       int skip_this = 0;
831 
832       if (inpattern)
833         {
834           const char *pattern = *inpattern;
835 
836           if (!pattern)
837             break; /* End of array.  */
838           inpattern++;
839 
840           if (!*pattern)
841             continue;
842 
843           pat = name_to_utf8 (pattern, 0);
844         }
845       else /* Read Nul or LF delimited pattern from files_from_stream.  */
846         {
847           int c;
848           char namebuf[4096];
849           size_t n = 0;
850 
851           for (;;)
852             {
853               if ((c = es_getc (files_from_stream)) == EOF)
854                 {
855                   if (es_ferror (files_from_stream))
856                     {
857                       err = gpg_error_from_syserror ();
858                       log_error ("error reading '%s': %s\n",
859                                  files_from, gpg_strerror (err));
860                       goto leave;
861                     }
862                   c = null_names ? 0 : '\n';
863                   eof_seen = 1;
864                 }
865               if (n >= sizeof namebuf - 1)
866                 {
867                   if (!skip_this)
868                     {
869                       skip_this = 1;
870                       log_error ("error reading '%s': %s\n",
871                                  files_from, "filename too long");
872                     }
873                 }
874               else
875                 namebuf[n++] = c;
876 
877               if (null_names)
878                 {
879                   if (!c)
880                     {
881                       namebuf[n] = 0;
882                       break;
883                     }
884                 }
885               else /* Shall be LF delimited.  */
886                 {
887                   if (!c)
888                     {
889                       if (!skip_this)
890                         {
891                           skip_this = 1;
892                           log_error ("error reading '%s': %s\n",
893                                      files_from, "filename with embedded Nul");
894                         }
895                     }
896                   else if ( c == '\n' )
897                     {
898                       namebuf[n] = 0;
899                       ascii_trim_spaces (namebuf);
900                       n = strlen (namebuf);
901                       break;
902                     }
903                 }
904             }
905 
906           if (skip_this || n < 2)
907             continue;
908 
909           pat = name_to_utf8 (namebuf, opt.utf8strings);
910         }
911 
912       if (!pat)
913         {
914           err = gpg_error_from_syserror ();
915           log_error ("memory allocation problem: %s\n", gpg_strerror (err));
916           goto leave;
917         }
918       for (p=pat; *p; p++)
919         if (*p == '\\')
920           *p = '/';
921 
922       if (opt.verbose > 1)
923         log_info ("scanning '%s'\n", pat);
924 
925       start_tail = scanctrl->flist_tail;
926       if (skip_this || !pattern_valid_p (pat))
927         log_error ("skipping invalid name '%s'\n", pat);
928       else if (!add_entry (pat, NULL, scanctrl)
929                && *start_tail && ((*start_tail)->typeflag & TF_DIRECTORY))
930         scan_recursive (pat, scanctrl);
931 
932       xfree (pat);
933     }
934 
935   if (files_from_stream && files_from_stream != es_stdin)
936     es_fclose (files_from_stream);
937 
938   if (opt.outfile)
939     {
940       if (!strcmp (opt.outfile, "-"))
941         outstream = es_stdout;
942       else
943         outstream = es_fopen (opt.outfile, "wb");
944       if (!outstream)
945         {
946           err = gpg_error_from_syserror ();
947           goto leave;
948         }
949     }
950   else
951     {
952       outstream = es_stdout;
953     }
954 
955   if (outstream == es_stdout)
956     es_set_binary (es_stdout);
957 
958   if (encrypt || sign)
959     {
960       cipher_stream = outstream;
961       outstream = es_fopenmem (0, "rwb");
962       if (! outstream)
963         {
964           err = gpg_error_from_syserror ();
965           goto leave;
966         }
967     }
968 
969   for (hdr = scanctrl->flist; hdr; hdr = hdr->next)
970     {
971       err = write_file (outstream, hdr);
972       if (err)
973         goto leave;
974     }
975   err = write_eof_mark (outstream);
976   if (err)
977     goto leave;
978 
979   if (encrypt || sign)
980     {
981       strlist_t arg;
982       ccparray_t ccp;
983       const char **argv;
984 
985       err = es_fseek (outstream, 0, SEEK_SET);
986       if (err)
987         goto leave;
988 
989       /* '--encrypt' may be combined with '--symmetric', but 'encrypt'
990          is set either way.  Clear it if no recipients are specified.
991          XXX: Fix command handling.  */
992       if (opt.symmetric && opt.recipients == NULL)
993         encrypt = 0;
994 
995       ccparray_init (&ccp, 0);
996       if (encrypt)
997         ccparray_put (&ccp, "--encrypt");
998       if (sign)
999         ccparray_put (&ccp, "--sign");
1000       if (opt.user)
1001         {
1002           ccparray_put (&ccp, "--local-user");
1003           ccparray_put (&ccp, opt.user);
1004         }
1005       if (opt.symmetric)
1006         ccparray_put (&ccp, "--symmetric");
1007       for (arg = opt.recipients; arg; arg = arg->next)
1008         {
1009           ccparray_put (&ccp, "--recipient");
1010           ccparray_put (&ccp, arg->d);
1011         }
1012       for (arg = opt.gpg_arguments; arg; arg = arg->next)
1013         ccparray_put (&ccp, arg->d);
1014 
1015       ccparray_put (&ccp, NULL);
1016       argv = ccparray_get (&ccp, NULL);
1017       if (!argv)
1018         {
1019           err = gpg_error_from_syserror ();
1020           goto leave;
1021         }
1022 
1023       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
1024                                     outstream, NULL, cipher_stream, NULL, NULL);
1025       xfree (argv);
1026       if (err)
1027         goto leave;
1028     }
1029 
1030  leave:
1031   if (!err)
1032     {
1033       gpg_error_t first_err;
1034       if (outstream != es_stdout)
1035         first_err = es_fclose (outstream);
1036       else
1037         first_err = es_fflush (outstream);
1038       outstream = NULL;
1039       if (cipher_stream != es_stdout)
1040         err = es_fclose (cipher_stream);
1041       else
1042         err = es_fflush (cipher_stream);
1043       cipher_stream = NULL;
1044       if (! err)
1045         err = first_err;
1046     }
1047   if (err)
1048     {
1049       log_error ("creating tarball '%s' failed: %s\n",
1050                  opt.outfile ? opt.outfile : "-", gpg_strerror (err));
1051       if (outstream && outstream != es_stdout)
1052         es_fclose (outstream);
1053       if (cipher_stream && cipher_stream != es_stdout)
1054         es_fclose (cipher_stream);
1055       if (opt.outfile)
1056         gnupg_remove (opt.outfile);
1057     }
1058   scanctrl->flist_tail = NULL;
1059   while ( (hdr = scanctrl->flist) )
1060     {
1061       scanctrl->flist = hdr->next;
1062       xfree (hdr);
1063     }
1064   return err;
1065 }
1066