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