1 /* gpgtar-create.c - Create a TAR archive
2 * Copyright (C) 2010 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
25 #include <sys/types.h>
28 #ifdef HAVE_W32_SYSTEM
29 # define WIN32_LEAN_AND_MEAN
31 #else /*!HAVE_W32_SYSTEM*/
35 #endif /*!HAVE_W32_SYSTEM*/
39 #include "../common/exectool.h"
40 #include "../common/sysutils.h"
41 #include "../common/ccparray.h"
45 #define lstat(a,b) stat ((a), (b))
49 /* Object to control the file scanning. */
51 typedef struct scanctrl_s *scanctrl_t;
55 tar_header_t *flist_tail;
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
66 fillup_entry_w32 (tar_header_t hdr)
70 WIN32_FILE_ATTRIBUTE_DATA fad;
73 for (p=hdr->name; *p; p++)
76 wfname = native_to_wchar (hdr->name);
77 for (p=hdr->name; *p; p++)
82 log_error ("error converting '%s': %s\n", hdr->name, w32_strerror (-1));
83 return gpg_error_from_syserror ();
85 if (!GetFileAttributesExW (wfname, GetFileExInfoStandard, &fad))
87 log_error ("error stat-ing '%s': %s\n", hdr->name, w32_strerror (-1));
89 return gpg_error_from_syserror ();
93 attr = fad.dwFileAttributes;
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;
104 hdr->typeflag = TF_REGULAR;
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. */
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)
122 hdr->mtime = (((unsigned long long)fad.ftLastWriteTime.dwHighDateTime << 32)
123 | fad.ftLastWriteTime.dwLowDateTime);
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. */
132 #endif /*HAVE_W32_SYSTEM*/
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
139 fillup_entry_posix (tar_header_t hdr)
144 if (lstat (hdr->name, &sbuf))
146 err = gpg_error_from_syserror ();
147 log_error ("error stat-ing '%s': %s\n", hdr->name, gpg_strerror (err));
151 if (S_ISREG (sbuf.st_mode))
152 hdr->typeflag = TF_REGULAR;
153 else if (S_ISDIR (sbuf.st_mode))
154 hdr->typeflag = TF_DIRECTORY;
155 else if (S_ISCHR (sbuf.st_mode))
156 hdr->typeflag = TF_CHARDEV;
157 else if (S_ISBLK (sbuf.st_mode))
158 hdr->typeflag = TF_BLOCKDEV;
159 else if (S_ISFIFO (sbuf.st_mode))
160 hdr->typeflag = TF_FIFO;
161 else if (S_ISLNK (sbuf.st_mode))
162 hdr->typeflag = TF_SYMLINK;
164 hdr->typeflag = TF_NOTSUP;
166 /* FIXME: Save DEV and INO? */
168 /* Set the USTAR defined mode bits using the system macros. */
169 if (sbuf.st_mode & S_IRUSR)
171 if (sbuf.st_mode & S_IWUSR)
173 if (sbuf.st_mode & S_IXUSR)
175 if (sbuf.st_mode & S_IRGRP)
177 if (sbuf.st_mode & S_IWGRP)
179 if (sbuf.st_mode & S_IXGRP)
181 if (sbuf.st_mode & S_IROTH)
183 if (sbuf.st_mode & S_IWOTH)
185 if (sbuf.st_mode & S_IXOTH)
188 if (sbuf.st_mode & S_IXUID)
192 if (sbuf.st_mode & S_IXGID)
196 if (sbuf.st_mode & S_ISVTX)
200 hdr->nlink = sbuf.st_nlink;
202 hdr->uid = sbuf.st_uid;
203 hdr->gid = sbuf.st_gid;
205 /* Only set the size for a regular file. */
206 if (hdr->typeflag == TF_REGULAR)
207 hdr->size = sbuf.st_size;
209 hdr->mtime = sbuf.st_mtime;
213 #endif /*!HAVE_W32_SYSTEM*/
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
221 add_entry (const char *dname, const char *entryname, scanctrl_t scanctrl)
226 size_t dnamelen = strlen (dname);
230 hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1
231 + (entryname? strlen (entryname) : 0) + 1);
233 return gpg_error_from_syserror ();
235 p = stpcpy (hdr->name, dname);
238 if (dname[dnamelen-1] != '/')
240 strcpy (p, entryname);
244 if (hdr->name[dnamelen-1] == '/')
245 hdr->name[dnamelen-1] = 0;
247 #ifdef HAVE_DOSISH_SYSTEM
248 err = fillup_entry_w32 (hdr);
250 err = fillup_entry_posix (hdr);
257 gpgtar_print_header (hdr, log_get_stream ());
258 *scanctrl->flist_tail = hdr;
259 scanctrl->flist_tail = &hdr->next;
267 scan_directory (const char *dname, scanctrl_t scanctrl)
271 #ifdef HAVE_W32_SYSTEM
273 HANDLE hd = INVALID_HANDLE_VALUE;
277 return 0; /* An empty directory name has no entries. */
283 fname = xtrymalloc (strlen (dname) + 2 + 2 + 1);
286 err = gpg_error_from_syserror ();
289 if (!strcmp (dname, "/"))
290 strcpy (fname, "/*"); /* Trailing slash is not allowed. */
291 else if (!strcmp (dname, "."))
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), "/*");
298 strcpy (fname, dname);
300 for (p=fname; *p; p++)
303 wfname = native_to_wchar (fname);
307 err = gpg_error_from_syserror ();
308 log_error (_("error reading directory '%s': %s\n"),
309 dname, gpg_strerror (err));
312 hd = FindFirstFileW (wfname, &fi);
313 if (hd == INVALID_HANDLE_VALUE)
315 err = gpg_error_from_syserror ();
316 log_error (_("error reading directory '%s': %s\n"),
317 dname, w32_strerror (-1));
326 char *fname = wchar_to_native (fi.cFileName);
329 err = gpg_error_from_syserror ();
330 log_error ("error converting filename: %s\n", w32_strerror (-1));
333 for (p=fname; *p; 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);
341 err = add_entry (dname, fname, scanctrl);
344 while (!err && FindNextFileW (hd, &fi));
347 else if (GetLastError () == ERROR_NO_MORE_FILES)
351 err = gpg_error_from_syserror ();
352 log_error (_("error reading directory '%s': %s\n"),
353 dname, w32_strerror (-1));
357 if (hd != INVALID_HANDLE_VALUE)
360 #else /*!HAVE_W32_SYSTEM*/
365 return 0; /* An empty directory name has no entries. */
367 dir = opendir (dname);
370 err = gpg_error_from_syserror ();
371 log_error (_("error reading directory '%s': %s\n"),
372 dname, gpg_strerror (err));
376 while ((de = readdir (dir)))
378 if (!strcmp (de->d_name, "." ) || !strcmp (de->d_name, ".."))
379 continue; /* Skip self and parent dir entry. */
381 err = add_entry (dname, de->d_name, scanctrl);
388 #endif /*!HAVE_W32_SYSTEM*/
394 scan_recursive (const char *dname, scanctrl_t scanctrl)
397 tar_header_t hdr, *start_tail, *stop_tail;
399 if (scanctrl->nestlevel > 200)
401 log_error ("directories too deeply nested\n");
402 return gpg_error (GPG_ERR_RESOURCE_LIMIT);
404 scanctrl->nestlevel++;
406 assert (scanctrl->flist_tail);
407 start_tail = scanctrl->flist_tail;
408 scan_directory (dname, scanctrl);
409 stop_tail = scanctrl->flist_tail;
411 for (; hdr && hdr != *stop_tail; hdr = hdr->next)
412 if (hdr->typeflag == TF_DIRECTORY)
415 log_info ("scanning directory '%s'\n", hdr->name);
416 scan_recursive (hdr->name, scanctrl);
419 scanctrl->nestlevel--;
424 /* Returns true if PATTERN is acceptable. */
426 pattern_valid_p (const char *pattern)
430 if (*pattern == '.' && pattern[1] == '.')
432 if (*pattern == '/' || *pattern == DIRSEP_C)
433 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*/
441 return 1; /* Okay. */
447 store_xoctal (char *buffer, size_t length, unsigned long long value)
451 unsigned long long v;
457 p = pend = buffer + length;
458 *--p = 0; /* Nul byte. */
462 *--p = '0' + (v % 8);
473 else /* Does not fit into the field. Store as binary number. */
477 p = pend = buffer + length;
492 *p |= 0x80; /* Set binary flag. */
501 store_uname (char *buffer, size_t length, unsigned long uid)
503 static int initialized;
504 static unsigned long lastuid;
505 static char lastuname[32];
507 if (!initialized || uid != lastuid)
509 #ifdef HAVE_W32_SYSTEM
510 mem2str (lastuname, uid? "user":"root", sizeof lastuname);
512 struct passwd *pw = getpwuid (uid);
517 mem2str (lastuname, pw->pw_name, sizeof lastuname);
520 log_info ("failed to get name for uid %lu\n", uid);
525 mem2str (buffer, lastuname, length);
530 store_gname (char *buffer, size_t length, unsigned long gid)
532 static int initialized;
533 static unsigned long lastgid;
534 static char lastgname[32];
536 if (!initialized || gid != lastgid)
538 #ifdef HAVE_W32_SYSTEM
539 mem2str (lastgname, gid? "users":"root", sizeof lastgname);
541 struct group *gr = getgrgid (gid);
546 mem2str (lastgname, gr->gr_name, sizeof lastgname);
549 log_info ("failed to get name for gid %lu\n", gid);
554 mem2str (buffer, lastgname, length);
559 build_header (void *record, tar_header_t hdr)
562 struct ustar_raw_header *raw = record;
564 unsigned long chksum;
567 memset (record, 0, RECORDSIZE);
569 /* Store name and prefix. */
570 namelen = strlen (hdr->name);
571 if (namelen < sizeof raw->name)
572 memcpy (raw->name, hdr->name, namelen);
575 n = (namelen < sizeof raw->prefix)? namelen : sizeof raw->prefix;
577 if (hdr->name[n] == '/')
579 if (namelen - n < sizeof raw->name)
581 /* Note that the N is < sizeof prefix and that the
582 delimiting slash is not stored. */
583 memcpy (raw->prefix, hdr->name, n);
584 memcpy (raw->name, hdr->name+n+1, namelen - n);
588 err = gpg_error (GPG_ERR_TOO_LARGE);
589 log_error ("error storing file '%s': %s\n",
590 hdr->name, gpg_strerror (err));
595 store_xoctal (raw->mode, sizeof raw->mode, hdr->mode);
596 store_xoctal (raw->uid, sizeof raw->uid, hdr->uid);
597 store_xoctal (raw->gid, sizeof raw->gid, hdr->gid);
598 store_xoctal (raw->size, sizeof raw->size, hdr->size);
599 store_xoctal (raw->mtime, sizeof raw->mtime, hdr->mtime);
601 switch (hdr->typeflag)
603 case TF_REGULAR: raw->typeflag[0] = '0'; break;
604 case TF_HARDLINK: raw->typeflag[0] = '1'; break;
605 case TF_SYMLINK: raw->typeflag[0] = '2'; break;
606 case TF_CHARDEV: raw->typeflag[0] = '3'; break;
607 case TF_BLOCKDEV: raw->typeflag[0] = '4'; break;
608 case TF_DIRECTORY: raw->typeflag[0] = '5'; break;
609 case TF_FIFO: raw->typeflag[0] = '6'; break;
610 default: return gpg_error (GPG_ERR_NOT_SUPPORTED);
613 memcpy (raw->magic, "ustar", 6);
614 raw->version[0] = '0';
615 raw->version[1] = '0';
617 store_uname (raw->uname, sizeof raw->uname, hdr->uid);
618 store_gname (raw->gname, sizeof raw->gname, hdr->gid);
620 #ifndef HAVE_W32_SYSTEM
621 if (hdr->typeflag == TF_SYMLINK)
625 nread = readlink (hdr->name, raw->linkname, sizeof raw->linkname -1);
628 err = gpg_error_from_syserror ();
629 log_error ("error reading symlink '%s': %s\n",
630 hdr->name, gpg_strerror (err));
633 raw->linkname[nread] = 0;
635 #endif /*HAVE_W32_SYSTEM*/
637 /* Compute the checksum. */
638 memset (raw->checksum, ' ', sizeof raw->checksum);
641 for (n=0; n < RECORDSIZE; n++)
643 store_xoctal (raw->checksum, sizeof raw->checksum - 1, chksum);
644 raw->checksum[7] = ' ';
651 write_file (estream_t stream, tar_header_t hdr)
654 char record[RECORDSIZE];
656 size_t nread, nbytes;
659 err = build_header (record, hdr);
662 if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
664 log_info ("skipping unsupported file '%s'\n", hdr->name);
670 if (hdr->typeflag == TF_REGULAR)
672 infp = es_fopen (hdr->name, "rb");
675 err = gpg_error_from_syserror ();
676 log_error ("can't open '%s': %s - skipped\n",
677 hdr->name, gpg_strerror (err));
684 err = write_record (stream, record);
688 if (hdr->typeflag == TF_REGULAR)
690 hdr->nrecords = (hdr->size + RECORDSIZE-1)/RECORDSIZE;
692 while (hdr->nrecords--)
694 nbytes = hdr->nrecords? RECORDSIZE : (hdr->size % RECORDSIZE);
697 nread = es_fread (record, 1, nbytes, infp);
700 err = gpg_error_from_syserror ();
701 log_error ("error reading file '%s': %s%s\n",
702 hdr->name, gpg_strerror (err),
703 any? " (file shrunk?)":"");
707 err = write_record (stream, record);
711 nread = es_fread (record, 1, 1, infp);
713 log_info ("note: file '%s' has grown\n", hdr->name);
719 else if ((err = es_fclose (infp)))
720 log_error ("error closing file '%s': %s\n", hdr->name, gpg_strerror (err));
727 write_eof_mark (estream_t stream)
730 char record[RECORDSIZE];
732 memset (record, 0, sizeof record);
733 err = write_record (stream, record);
735 err = write_record (stream, record);
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
745 gpgtar_create (char **inpattern, int encrypt, int sign)
748 struct scanctrl_s scanctrl_buffer;
749 scanctrl_t scanctrl = &scanctrl_buffer;
750 tar_header_t hdr, *start_tail;
751 estream_t outstream = NULL;
752 estream_t cipher_stream = NULL;
756 es_set_binary (es_stdin);
758 memset (scanctrl, 0, sizeof *scanctrl);
759 scanctrl->flist_tail = &scanctrl->flist;
768 const char *pattern = *inpattern;
771 break; /* End of array. */
777 pat = xtrystrdup (pattern);
779 else /* Read null delimited pattern from stdin. */
787 if ((c = es_getc (es_stdin)) == EOF)
789 if (es_ferror (es_stdin))
791 err = gpg_error_from_syserror ();
792 log_error ("error reading '%s': %s\n",
793 "[stdin]", strerror (errno));
796 /* Note: The Nul is a delimiter and not a terminator. */
800 if (n >= sizeof namebuf - 1)
805 log_error ("error reading '%s': %s\n",
806 "[stdin]", "filename too long");
818 if (skip_this || n < 2)
821 pat = xtrystrdup (namebuf);
826 err = gpg_error_from_syserror ();
827 log_error ("memory allocation problem: %s\n", gpg_strerror (err));
835 log_info ("scanning '%s'\n", pat);
837 start_tail = scanctrl->flist_tail;
838 if (skip_this || !pattern_valid_p (pat))
839 log_error ("skipping invalid name '%s'\n", pat);
840 else if (!add_entry (pat, NULL, scanctrl)
841 && *start_tail && ((*start_tail)->typeflag & TF_DIRECTORY))
842 scan_recursive (pat, scanctrl);
849 if (!strcmp (opt.outfile, "-"))
850 outstream = es_stdout;
852 outstream = es_fopen (opt.outfile, "wb");
855 err = gpg_error_from_syserror ();
861 outstream = es_stdout;
864 if (outstream == es_stdout)
865 es_set_binary (es_stdout);
869 cipher_stream = outstream;
870 outstream = es_fopenmem (0, "rwb");
873 err = gpg_error_from_syserror ();
878 for (hdr = scanctrl->flist; hdr; hdr = hdr->next)
880 err = write_file (outstream, hdr);
884 err = write_eof_mark (outstream);
894 err = es_fseek (outstream, 0, SEEK_SET);
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 if (opt.symmetric && opt.recipients == NULL)
904 ccparray_init (&ccp, 0);
906 ccparray_put (&ccp, "--encrypt");
908 ccparray_put (&ccp, "--sign");
911 ccparray_put (&ccp, "--local-user");
912 ccparray_put (&ccp, opt.user);
915 ccparray_put (&ccp, "--symmetric");
916 for (arg = opt.recipients; arg; arg = arg->next)
918 ccparray_put (&ccp, "--recipient");
919 ccparray_put (&ccp, arg->d);
921 for (arg = opt.gpg_arguments; arg; arg = arg->next)
922 ccparray_put (&ccp, arg->d);
924 ccparray_put (&ccp, NULL);
925 argv = ccparray_get (&ccp, NULL);
928 err = gpg_error_from_syserror ();
932 err = gnupg_exec_tool_stream (opt.gpg_program, argv,
933 outstream, NULL, cipher_stream, NULL, NULL);
942 gpg_error_t first_err;
943 if (outstream != es_stdout)
944 first_err = es_fclose (outstream);
946 first_err = es_fflush (outstream);
948 if (cipher_stream != es_stdout)
949 err = es_fclose (cipher_stream);
951 err = es_fflush (cipher_stream);
952 cipher_stream = NULL;
958 log_error ("creating tarball '%s' failed: %s\n",
959 opt.outfile ? opt.outfile : "-", gpg_strerror (err));
960 if (outstream && outstream != es_stdout)
961 es_fclose (outstream);
962 if (cipher_stream && cipher_stream != es_stdout)
963 es_fclose (cipher_stream);
965 gnupg_remove (opt.outfile);
967 scanctrl->flist_tail = NULL;
968 while ( (hdr = scanctrl->flist) )
970 scanctrl->flist = hdr->next;