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 <http://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 88 : fillup_entry_posix (tar_header_t hdr)
140 : {
141 : gpg_error_t err;
142 : struct stat sbuf;
143 :
144 88 : 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 88 : if (S_ISREG (sbuf.st_mode))
152 87 : hdr->typeflag = TF_REGULAR;
153 1 : else if (S_ISDIR (sbuf.st_mode))
154 1 : 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 88 : if (sbuf.st_mode & S_IRUSR)
170 88 : hdr->mode |= 0400;
171 88 : if (sbuf.st_mode & S_IWUSR)
172 88 : hdr->mode |= 0200;
173 88 : if (sbuf.st_mode & S_IXUSR)
174 1 : hdr->mode |= 0100;
175 88 : if (sbuf.st_mode & S_IRGRP)
176 58 : hdr->mode |= 0040;
177 88 : if (sbuf.st_mode & S_IWGRP)
178 0 : hdr->mode |= 0020;
179 88 : if (sbuf.st_mode & S_IXGRP)
180 0 : hdr->mode |= 0010;
181 88 : if (sbuf.st_mode & S_IROTH)
182 58 : hdr->mode |= 0004;
183 88 : if (sbuf.st_mode & S_IWOTH)
184 0 : hdr->mode |= 0002;
185 88 : 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 88 : if (sbuf.st_mode & S_ISVTX)
197 0 : hdr->mode |= 01000;
198 : #endif
199 :
200 88 : hdr->nlink = sbuf.st_nlink;
201 :
202 88 : hdr->uid = sbuf.st_uid;
203 88 : hdr->gid = sbuf.st_gid;
204 :
205 : /* Only set the size for a regular file. */
206 88 : if (hdr->typeflag == TF_REGULAR)
207 87 : hdr->size = sbuf.st_size;
208 :
209 88 : hdr->mtime = sbuf.st_mtime;
210 :
211 88 : 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 88 : 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 88 : size_t dnamelen = strlen (dname);
227 :
228 88 : assert (dnamelen);
229 :
230 88 : hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1
231 : + (entryname? strlen (entryname) : 0) + 1);
232 88 : if (!hdr)
233 0 : return gpg_error_from_syserror ();
234 :
235 88 : p = stpcpy (hdr->name, dname);
236 88 : if (entryname)
237 : {
238 18 : if (dname[dnamelen-1] != '/')
239 18 : *p++ = '/';
240 18 : strcpy (p, entryname);
241 : }
242 : else
243 : {
244 70 : 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 88 : err = fillup_entry_posix (hdr);
251 : #endif
252 88 : if (err)
253 0 : xfree (hdr);
254 : else
255 : {
256 88 : if (opt.verbose)
257 0 : gpgtar_print_header (hdr, log_get_stream ());
258 88 : *scanctrl->flist_tail = hdr;
259 88 : scanctrl->flist_tail = &hdr->next;
260 : }
261 :
262 88 : return 0;
263 : }
264 :
265 :
266 : static gpg_error_t
267 1 : scan_directory (const char *dname, scanctrl_t scanctrl)
268 : {
269 1 : 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 1 : if (!*dname)
365 0 : return 0; /* An empty directory name has no entries. */
366 :
367 1 : dir = opendir (dname);
368 1 : 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 22 : while ((de = readdir (dir)))
377 : {
378 20 : if (!strcmp (de->d_name, "." ) || !strcmp (de->d_name, ".."))
379 2 : continue; /* Skip self and parent dir entry. */
380 :
381 18 : err = add_entry (dname, de->d_name, scanctrl);
382 18 : if (err)
383 0 : goto leave;
384 : }
385 :
386 : leave:
387 1 : closedir (dir);
388 : #endif /*!HAVE_W32_SYSTEM*/
389 1 : return err;
390 : }
391 :
392 :
393 : static gpg_error_t
394 1 : scan_recursive (const char *dname, scanctrl_t scanctrl)
395 : {
396 1 : gpg_error_t err = 0;
397 : tar_header_t hdr, *start_tail, *stop_tail;
398 :
399 1 : 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 1 : scanctrl->nestlevel++;
405 :
406 1 : assert (scanctrl->flist_tail);
407 1 : start_tail = scanctrl->flist_tail;
408 1 : scan_directory (dname, scanctrl);
409 1 : stop_tail = scanctrl->flist_tail;
410 1 : hdr = *start_tail;
411 19 : for (; hdr && hdr != *stop_tail; hdr = hdr->next)
412 18 : if (hdr->typeflag == TF_DIRECTORY)
413 : {
414 0 : if (opt.verbose > 1)
415 0 : log_info ("scanning directory '%s'\n", hdr->name);
416 0 : scan_recursive (hdr->name, scanctrl);
417 : }
418 :
419 1 : scanctrl->nestlevel--;
420 1 : return err;
421 : }
422 :
423 :
424 : /* Returns true if PATTERN is acceptable. */
425 : static int
426 70 : pattern_valid_p (const char *pattern)
427 : {
428 70 : if (!*pattern)
429 0 : return 0;
430 70 : if (*pattern == '.' && pattern[1] == '.')
431 0 : return 0;
432 70 : 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 70 : return 1; /* Okay. */
442 : }
443 :
444 :
445 :
446 : static void
447 528 : 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 528 : assert (length > 1);
454 :
455 528 : v = value;
456 528 : n = length;
457 528 : p = pend = buffer + length;
458 528 : *--p = 0; /* Nul byte. */
459 528 : n--;
460 : do
461 : {
462 2732 : *--p = '0' + (v % 8);
463 2732 : v /= 8;
464 2732 : n--;
465 : }
466 2732 : while (v && n);
467 528 : if (!v)
468 : {
469 : /* Pad. */
470 2108 : for ( ; n; n--)
471 1580 : *--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 528 : }
498 :
499 :
500 : static void
501 88 : 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 88 : 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 88 : mem2str (buffer, lastuname, length);
526 88 : }
527 :
528 :
529 : static void
530 88 : 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 88 : 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 88 : mem2str (buffer, lastgname, length);
555 88 : }
556 :
557 :
558 : static gpg_error_t
559 88 : build_header (void *record, tar_header_t hdr)
560 : {
561 : gpg_error_t err;
562 88 : struct ustar_raw_header *raw = record;
563 : size_t namelen, n;
564 : unsigned long chksum;
565 : unsigned char *p;
566 :
567 88 : memset (record, 0, RECORDSIZE);
568 :
569 : /* Store name and prefix. */
570 88 : namelen = strlen (hdr->name);
571 88 : if (namelen < sizeof raw->name)
572 88 : 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 88 : store_xoctal (raw->mode, sizeof raw->mode, hdr->mode);
596 88 : store_xoctal (raw->uid, sizeof raw->uid, hdr->uid);
597 88 : store_xoctal (raw->gid, sizeof raw->gid, hdr->gid);
598 88 : store_xoctal (raw->size, sizeof raw->size, hdr->size);
599 88 : store_xoctal (raw->mtime, sizeof raw->mtime, hdr->mtime);
600 :
601 88 : 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 1 : 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 88 : memcpy (raw->magic, "ustar", 6);
614 88 : raw->version[0] = '0';
615 88 : raw->version[1] = '0';
616 :
617 88 : store_uname (raw->uname, sizeof raw->uname, hdr->uid);
618 88 : store_gname (raw->gname, sizeof raw->gname, hdr->gid);
619 :
620 : #ifndef HAVE_W32_SYSTEM
621 88 : 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 88 : memset (raw->checksum, ' ', sizeof raw->checksum);
639 88 : chksum = 0;
640 88 : p = record;
641 45144 : for (n=0; n < RECORDSIZE; n++)
642 45056 : chksum += *p++;
643 88 : store_xoctal (raw->checksum, sizeof raw->checksum - 1, chksum);
644 88 : raw->checksum[7] = ' ';
645 :
646 88 : return 0;
647 : }
648 :
649 :
650 : static gpg_error_t
651 88 : 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 88 : err = build_header (record, hdr);
660 88 : 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 88 : 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 1 : infp = NULL;
683 :
684 88 : err = write_record (stream, record);
685 88 : if (err)
686 0 : goto leave;
687 :
688 88 : 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 88 : if (err)
718 0 : es_fclose (infp);
719 88 : else if ((err = es_fclose (infp)))
720 0 : log_error ("error closing file '%s': %s\n", hdr->name, gpg_strerror (err));
721 :
722 88 : 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 88 : while (!eof_seen)
762 : {
763 : char *pat, *p;
764 79 : int skip_this = 0;
765 :
766 79 : if (inpattern)
767 : {
768 79 : const char *pattern = *inpattern;
769 :
770 79 : if (!pattern)
771 9 : break; /* End of array. */
772 70 : inpattern++;
773 :
774 70 : if (!*pattern)
775 0 : continue;
776 :
777 70 : 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 70 : 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 676 : for (p=pat; *p; p++)
831 606 : if (*p == '\\')
832 0 : *p = '/';
833 :
834 70 : if (opt.verbose > 1)
835 0 : log_info ("scanning '%s'\n", pat);
836 :
837 70 : start_tail = scanctrl->flist_tail;
838 70 : if (skip_this || !pattern_valid_p (pat))
839 0 : log_error ("skipping invalid name '%s'\n", pat);
840 70 : else if (!add_entry (pat, NULL, scanctrl)
841 70 : && *start_tail && ((*start_tail)->typeflag & TF_DIRECTORY))
842 1 : scan_recursive (pat, scanctrl);
843 :
844 70 : 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 : log_error (_("can't create '%s': %s\n"),
857 : opt.outfile, gpg_strerror (err));
858 0 : goto leave;
859 : }
860 : }
861 : else
862 : {
863 0 : outstream = es_stdout;
864 : }
865 :
866 9 : if (outstream == es_stdout)
867 0 : es_set_binary (es_stdout);
868 :
869 9 : if (encrypt || sign)
870 : {
871 6 : cipher_stream = outstream;
872 6 : outstream = es_fopenmem (0, "rwb");
873 6 : if (! outstream)
874 : {
875 0 : err = gpg_error_from_syserror ();
876 0 : goto leave;
877 : }
878 : }
879 :
880 97 : for (hdr = scanctrl->flist; hdr; hdr = hdr->next)
881 : {
882 88 : err = write_file (outstream, hdr);
883 88 : if (err)
884 0 : goto leave;
885 : }
886 9 : err = write_eof_mark (outstream);
887 9 : if (err)
888 0 : goto leave;
889 :
890 9 : if (encrypt || sign)
891 : {
892 : strlist_t arg;
893 : ccparray_t ccp;
894 : const char **argv;
895 :
896 6 : err = es_fseek (outstream, 0, SEEK_SET);
897 6 : if (err)
898 0 : goto leave;
899 :
900 : /* '--encrypt' may be combined with '--symmetric', but 'encrypt'
901 : is set either way. Clear it if no recipients are specified.
902 : XXX: Fix command handling. */
903 6 : if (opt.symmetric && opt.recipients == NULL)
904 2 : encrypt = 0;
905 :
906 6 : ccparray_init (&ccp, 0);
907 6 : if (encrypt)
908 3 : ccparray_put (&ccp, "--encrypt");
909 6 : if (sign)
910 3 : ccparray_put (&ccp, "--sign");
911 6 : if (opt.user)
912 : {
913 3 : ccparray_put (&ccp, "--local-user");
914 3 : ccparray_put (&ccp, opt.user);
915 : }
916 6 : if (opt.symmetric)
917 3 : ccparray_put (&ccp, "--symmetric");
918 9 : for (arg = opt.recipients; arg; arg = arg->next)
919 : {
920 3 : ccparray_put (&ccp, "--recipient");
921 3 : ccparray_put (&ccp, arg->d);
922 : }
923 22 : for (arg = opt.gpg_arguments; arg; arg = arg->next)
924 16 : ccparray_put (&ccp, arg->d);
925 :
926 6 : ccparray_put (&ccp, NULL);
927 6 : argv = ccparray_get (&ccp, NULL);
928 6 : if (!argv)
929 : {
930 0 : err = gpg_error_from_syserror ();
931 0 : goto leave;
932 : }
933 :
934 6 : err = gnupg_exec_tool_stream (opt.gpg_program, argv,
935 : outstream, NULL, cipher_stream, NULL, NULL);
936 6 : xfree (argv);
937 6 : if (err)
938 0 : goto leave;
939 : }
940 :
941 : leave:
942 9 : if (!err)
943 : {
944 : gpg_error_t first_err;
945 9 : if (outstream != es_stdout)
946 9 : first_err = es_fclose (outstream);
947 : else
948 0 : first_err = es_fflush (outstream);
949 9 : outstream = NULL;
950 9 : if (cipher_stream != es_stdout)
951 9 : err = es_fclose (cipher_stream);
952 : else
953 0 : err = es_fflush (cipher_stream);
954 9 : cipher_stream = NULL;
955 9 : if (! err)
956 9 : err = first_err;
957 : }
958 9 : if (err)
959 : {
960 0 : log_error ("creating tarball '%s' failed: %s\n",
961 : es_fname_get (outstream), gpg_strerror (err));
962 0 : if (outstream && outstream != es_stdout)
963 0 : es_fclose (outstream);
964 0 : if (cipher_stream && cipher_stream != es_stdout)
965 0 : es_fclose (cipher_stream);
966 0 : if (opt.outfile)
967 0 : gnupg_remove (opt.outfile);
968 : }
969 9 : scanctrl->flist_tail = NULL;
970 106 : while ( (hdr = scanctrl->flist) )
971 : {
972 88 : scanctrl->flist = hdr->next;
973 88 : xfree (hdr);
974 : }
975 9 : return err;
976 : }
|