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