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