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 <http://www.gnu.org/licenses/>.
25
#include <sys/types.h>
28
#ifdef HAVE_W32_SYSTEM
29
# define WIN32_LEAN_AND_MEAN
31
# include <fcntl.h> /* for setmode() */
32
#else /*!HAVE_W32_SYSTEM*/
36
#endif /*!HAVE_W32_SYSTEM*/
40
#include "../common/sysutils.h"
44
#define lstat(a,b) stat ((a), (b))
48
/* Object to control the file scanning. */
50
typedef struct scanctrl_s *scanctrl_t;
54
tar_header_t *flist_tail;
61
/* Given a fresh header object HDR with only the name field set, try
62
to gather all available info. This is the W32 version. */
63
#ifdef HAVE_W32_SYSTEM
65
fillup_entry_w32 (tar_header_t hdr)
69
WIN32_FILE_ATTRIBUTE_DATA fad;
72
for (p=hdr->name; *p; p++)
75
wfname = utf8_to_wchar (hdr->name);
76
for (p=hdr->name; *p; p++)
81
log_error ("error utf8-ing `%s': %s\n", hdr->name, w32_strerror (-1));
82
return gpg_error_from_syserror ();
84
if (!GetFileAttributesExW (wfname, GetFileExInfoStandard, &fad))
86
log_error ("error stat-ing `%s': %s\n", hdr->name, w32_strerror (-1));
88
return gpg_error_from_syserror ();
92
attr = fad.dwFileAttributes;
94
if ((attr & FILE_ATTRIBUTE_NORMAL))
95
hdr->typeflag = TF_REGULAR;
96
else if ((attr & FILE_ATTRIBUTE_DIRECTORY))
97
hdr->typeflag = TF_DIRECTORY;
98
else if ((attr & FILE_ATTRIBUTE_DEVICE))
99
hdr->typeflag = TF_NOTSUP;
100
else if ((attr & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_TEMPORARY)))
101
hdr->typeflag = TF_NOTSUP;
103
hdr->typeflag = TF_REGULAR;
105
/* Map some attributes to USTAR defined mode bits. */
106
hdr->mode = 0640; /* User may read and write, group only read. */
107
if ((attr & FILE_ATTRIBUTE_DIRECTORY))
108
hdr->mode |= 0110; /* Dirs are user and group executable. */
109
if ((attr & FILE_ATTRIBUTE_READONLY))
110
hdr->mode &= ~0200; /* Clear the user write bit. */
111
if ((attr & FILE_ATTRIBUTE_HIDDEN))
112
hdr->mode &= ~0707; /* Clear all user and other bits. */
113
if ((attr & FILE_ATTRIBUTE_SYSTEM))
114
hdr->mode |= 0004; /* Make it readable by other. */
116
/* Only set the size for a regular file. */
117
if (hdr->typeflag == TF_REGULAR)
118
hdr->size = (fad.nFileSizeHigh * (unsigned long long)(MAXDWORD+1)
121
hdr->mtime = (((unsigned long long)fad.ftLastWriteTime.dwHighDateTime << 32)
122
| fad.ftLastWriteTime.dwLowDateTime);
124
hdr->mtime = (((unsigned long long)fad.ftCreationTime.dwHighDateTime << 32)
125
| fad.ftCreationTime.dwLowDateTime);
126
hdr->mtime -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
127
hdr->mtime /= 10000000; /* Convert from 0.1us to seconds. */
131
#endif /*HAVE_W32_SYSTEM*/
134
/* Given a fresh header obje`<ct HDR with only the name field set, try
135
to gather all available info. This is the POSIX version. */
136
#ifndef HAVE_W32_SYSTEM
138
fillup_entry_posix (tar_header_t hdr)
143
if (lstat (hdr->name, &sbuf))
145
err = gpg_error_from_syserror ();
146
log_error ("error stat-ing `%s': %s\n", hdr->name, gpg_strerror (err));
150
if (S_ISREG (sbuf.st_mode))
151
hdr->typeflag = TF_REGULAR;
152
else if (S_ISDIR (sbuf.st_mode))
153
hdr->typeflag = TF_DIRECTORY;
154
else if (S_ISCHR (sbuf.st_mode))
155
hdr->typeflag = TF_CHARDEV;
156
else if (S_ISBLK (sbuf.st_mode))
157
hdr->typeflag = TF_BLOCKDEV;
158
else if (S_ISFIFO (sbuf.st_mode))
159
hdr->typeflag = TF_FIFO;
160
else if (S_ISLNK (sbuf.st_mode))
161
hdr->typeflag = TF_SYMLINK;
163
hdr->typeflag = TF_NOTSUP;
165
/* FIXME: Save DEV and INO? */
167
/* Set the USTAR defined mode bits using the system macros. */
168
if (sbuf.st_mode & S_IRUSR)
170
if (sbuf.st_mode & S_IWUSR)
172
if (sbuf.st_mode & S_IXUSR)
174
if (sbuf.st_mode & S_IRGRP)
176
if (sbuf.st_mode & S_IWGRP)
178
if (sbuf.st_mode & S_IXGRP)
180
if (sbuf.st_mode & S_IROTH)
182
if (sbuf.st_mode & S_IWOTH)
184
if (sbuf.st_mode & S_IXOTH)
187
if (sbuf.st_mode & S_IXUID)
191
if (sbuf.st_mode & S_IXGID)
195
if (sbuf.st_mode & S_ISVTX)
199
hdr->nlink = sbuf.st_nlink;
201
hdr->uid = sbuf.st_uid;
202
hdr->gid = sbuf.st_gid;
204
/* Only set the size for a regular file. */
205
if (hdr->typeflag == TF_REGULAR)
206
hdr->size = sbuf.st_size;
208
hdr->mtime = sbuf.st_mtime;
212
#endif /*!HAVE_W32_SYSTEM*/
215
/* Add a new entry. The name of a director entry is ENTRYNAME; if
216
that is NULL, DNAME is the name of the directory itself. Under
217
Windows ENTRYNAME shall have backslashes replaced by standard
220
add_entry (const char *dname, const char *entryname, scanctrl_t scanctrl)
225
size_t dnamelen = strlen (dname);
229
hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1
230
+ (entryname? strlen (entryname) : 0) + 1);
232
return gpg_error_from_syserror ();
234
p = stpcpy (hdr->name, dname);
237
if (dname[dnamelen-1] != '/')
239
strcpy (p, entryname);
243
if (hdr->name[dnamelen-1] == '/')
244
hdr->name[dnamelen-1] = 0;
246
#ifdef HAVE_DOSISH_SYSTEM
247
err = fillup_entry_w32 (hdr);
249
err = fillup_entry_posix (hdr);
256
gpgtar_print_header (hdr, es_stderr);
257
*scanctrl->flist_tail = hdr;
258
scanctrl->flist_tail = &hdr->next;
266
scan_directory (const char *dname, scanctrl_t scanctrl)
270
#ifdef HAVE_W32_SYSTEM
272
HANDLE hd = INVALID_HANDLE_VALUE;
276
return 0; /* An empty directory name has no entries. */
282
fname = xtrymalloc (strlen (dname) + 2 + 2 + 1);
285
err = gpg_error_from_syserror ();
288
if (!strcmp (dname, "/"))
289
strcpy (fname, "/*"); /* Trailing slash is not allowed. */
290
else if (!strcmp (dname, "."))
292
else if (*dname && dname[strlen (dname)-1] == '/')
293
strcpy (stpcpy (fname, dname), "*");
294
else if (*dname && dname[strlen (dname)-1] != '*')
295
strcpy (stpcpy (fname, dname), "/*");
297
strcpy (fname, dname);
299
for (p=fname; *p; p++)
302
wfname = utf8_to_wchar (fname);
306
err = gpg_error_from_syserror ();
307
log_error (_("error reading directory `%s': %s\n"),
308
dname, gpg_strerror (err));
311
hd = FindFirstFileW (wfname, &fi);
312
if (hd == INVALID_HANDLE_VALUE)
314
err = gpg_error_from_syserror ();
315
log_error (_("error reading directory `%s': %s\n"),
316
dname, w32_strerror (-1));
325
char *fname = wchar_to_utf8 (fi.cFileName);
328
err = gpg_error_from_syserror ();
329
log_error ("error utf8-ing filename: %s\n", w32_strerror (-1));
332
for (p=fname; *p; p++)
335
if (!strcmp (fname, "." ) || !strcmp (fname, ".."))
336
err = 0; /* Skip self and parent dir entry. */
337
else if (!strncmp (dname, "./", 2) && dname[2])
338
err = add_entry (dname+2, fname, scanctrl);
340
err = add_entry (dname, fname, scanctrl);
343
while (!err && FindNextFileW (hd, &fi));
346
else if (GetLastError () == ERROR_NO_MORE_FILES)
350
err = gpg_error_from_syserror ();
351
log_error (_("error reading directory `%s': %s\n"),
352
dname, w32_strerror (-1));
356
if (hd != INVALID_HANDLE_VALUE)
359
#else /*!HAVE_W32_SYSTEM*/
364
return 0; /* An empty directory name has no entries. */
366
dir = opendir (dname);
369
err = gpg_error_from_syserror ();
370
log_error (_("error reading directory `%s': %s\n"),
371
dname, gpg_strerror (err));
375
while ((de = readdir (dir)))
377
if (!strcmp (de->d_name, "." ) || !strcmp (de->d_name, ".."))
378
continue; /* Skip self and parent dir entry. */
380
err = add_entry (dname, de->d_name, scanctrl);
387
#endif /*!HAVE_W32_SYSTEM*/
393
scan_recursive (const char *dname, scanctrl_t scanctrl)
396
tar_header_t hdr, *start_tail, *stop_tail;
398
if (scanctrl->nestlevel > 200)
400
log_error ("directories too deeply nested\n");
401
return gpg_error (GPG_ERR_RESOURCE_LIMIT);
403
scanctrl->nestlevel++;
405
assert (scanctrl->flist_tail);
406
start_tail = scanctrl->flist_tail;
407
scan_directory (dname, scanctrl);
408
stop_tail = scanctrl->flist_tail;
410
for (; hdr && hdr != *stop_tail; hdr = hdr->next)
411
if (hdr->typeflag == TF_DIRECTORY)
414
log_info ("scanning directory `%s'\n", hdr->name);
415
scan_recursive (hdr->name, scanctrl);
418
scanctrl->nestlevel--;
423
/* Returns true if PATTERN is acceptable. */
425
pattern_valid_p (const char *pattern)
429
if (*pattern == '.' && pattern[1] == '.')
431
if (*pattern == '/' || *pattern == DIRSEP_C)
432
return 0; /* Absolute filenames are not supported. */
433
#ifdef HAVE_DRIVE_LETTERS
434
if (((*pattern >= 'a' && *pattern <= 'z')
435
|| (*pattern >= 'A' && *pattern <= 'Z'))
436
&& pattern[1] == ':')
437
return 0; /* Drive letter are not allowed either. */
438
#endif /*HAVE_DRIVE_LETTERS*/
440
return 1; /* Okay. */
446
store_xoctal (char *buffer, size_t length, unsigned long long value)
450
unsigned long long v;
456
p = pend = buffer + length;
457
*--p = 0; /* Nul byte. */
461
*--p = '0' + (v % 8);
472
else /* Does not fit into the field. Store as binary number. */
476
p = pend = buffer + length;
491
*p |= 0x80; /* Set binary flag. */
500
store_uname (char *buffer, size_t length, unsigned long uid)
502
static int initialized;
503
static unsigned long lastuid;
504
static char lastuname[32];
506
if (!initialized || uid != lastuid)
508
#ifdef HAVE_W32_SYSTEM
509
mem2str (lastuname, uid? "user":"root", sizeof lastuname);
511
struct passwd *pw = getpwuid (uid);
516
mem2str (lastuname, pw->pw_name, sizeof lastuname);
519
log_info ("failed to get name for uid %lu\n", uid);
524
mem2str (buffer, lastuname, length);
529
store_gname (char *buffer, size_t length, unsigned long gid)
531
static int initialized;
532
static unsigned long lastgid;
533
static char lastgname[32];
535
if (!initialized || gid != lastgid)
537
#ifdef HAVE_W32_SYSTEM
538
mem2str (lastgname, gid? "users":"root", sizeof lastgname);
540
struct group *gr = getgrgid (gid);
545
mem2str (lastgname, gr->gr_name, sizeof lastgname);
548
log_info ("failed to get name for gid %lu\n", gid);
553
mem2str (buffer, lastgname, length);
558
build_header (void *record, tar_header_t hdr)
561
struct ustar_raw_header *raw = record;
563
unsigned long chksum;
566
memset (record, 0, RECORDSIZE);
568
/* Store name and prefix. */
569
namelen = strlen (hdr->name);
570
if (namelen < sizeof raw->name)
571
memcpy (raw->name, hdr->name, namelen);
574
n = (namelen < sizeof raw->prefix)? namelen : sizeof raw->prefix;
576
if (hdr->name[n] == '/')
578
if (namelen - n < sizeof raw->name)
580
/* Note that the N is < sizeof prefix and that the
581
delimiting slash is not stored. */
582
memcpy (raw->prefix, hdr->name, n);
583
memcpy (raw->name, hdr->name+n+1, namelen - n);
587
err = gpg_error (GPG_ERR_TOO_LARGE);
588
log_error ("error storing file `%s': %s\n",
589
hdr->name, gpg_strerror (err));
594
store_xoctal (raw->mode, sizeof raw->mode, hdr->mode);
595
store_xoctal (raw->uid, sizeof raw->uid, hdr->uid);
596
store_xoctal (raw->gid, sizeof raw->gid, hdr->gid);
597
store_xoctal (raw->size, sizeof raw->size, hdr->size);
598
store_xoctal (raw->mtime, sizeof raw->mtime, hdr->mtime);
600
switch (hdr->typeflag)
602
case TF_REGULAR: raw->typeflag[0] = '0'; break;
603
case TF_HARDLINK: raw->typeflag[0] = '1'; break;
604
case TF_SYMLINK: raw->typeflag[0] = '2'; break;
605
case TF_CHARDEV: raw->typeflag[0] = '3'; break;
606
case TF_BLOCKDEV: raw->typeflag[0] = '4'; break;
607
case TF_DIRECTORY: raw->typeflag[0] = '5'; break;
608
case TF_FIFO: raw->typeflag[0] = '6'; break;
609
default: return gpg_error (GPG_ERR_NOT_SUPPORTED);
612
memcpy (raw->magic, "ustar", 6);
613
raw->version[0] = '0';
614
raw->version[1] = '0';
616
store_uname (raw->uname, sizeof raw->uname, hdr->uid);
617
store_gname (raw->gname, sizeof raw->gname, hdr->gid);
619
#ifndef HAVE_W32_SYSTEM
620
if (hdr->typeflag == TF_SYMLINK)
624
nread = readlink (hdr->name, raw->linkname, sizeof raw->linkname -1);
627
err = gpg_error_from_syserror ();
628
log_error ("error reading symlink `%s': %s\n",
629
hdr->name, gpg_strerror (err));
632
raw->linkname[nread] = 0;
634
#endif /*HAVE_W32_SYSTEM*/
636
/* Compute the checksum. */
637
memset (raw->checksum, ' ', sizeof raw->checksum);
640
for (n=0; n < RECORDSIZE; n++)
642
store_xoctal (raw->checksum, sizeof raw->checksum - 1, chksum);
643
raw->checksum[7] = ' ';
650
write_file (estream_t stream, tar_header_t hdr)
653
char record[RECORDSIZE];
655
size_t nread, nbytes;
658
err = build_header (record, hdr);
661
if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
663
log_info ("skipping unsupported file `%s'\n", hdr->name);
669
if (hdr->typeflag == TF_REGULAR)
671
infp = es_fopen (hdr->name, "rb");
674
err = gpg_error_from_syserror ();
675
log_error ("can't open `%s': %s - skipped\n",
676
hdr->name, gpg_strerror (err));
683
err = write_record (stream, record);
687
if (hdr->typeflag == TF_REGULAR)
689
hdr->nrecords = (hdr->size + RECORDSIZE-1)/RECORDSIZE;
691
while (hdr->nrecords--)
693
nbytes = hdr->nrecords? RECORDSIZE : (hdr->size % RECORDSIZE);
696
nread = es_fread (record, 1, nbytes, infp);
699
err = gpg_error_from_syserror ();
700
log_error ("error reading file `%s': %s%s\n",
701
hdr->name, gpg_strerror (err),
702
any? " (file shrunk?)":"");
706
err = write_record (stream, record);
710
nread = es_fread (record, 1, 1, infp);
712
log_info ("note: file `%s' has grown\n", hdr->name);
718
else if ((err = es_fclose (infp)))
719
log_error ("error closing file `%s': %s\n", hdr->name, gpg_strerror (err));
726
write_eof_mark (estream_t stream)
729
char record[RECORDSIZE];
731
memset (record, 0, sizeof record);
732
err = write_record (stream, record);
734
err = write_record (stream, record);
740
/* Create a new tarball using the names in the array INPATTERN. If
741
INPATTERN is NULL take the pattern as null terminated strings from
744
gpgtar_create (char **inpattern)
747
struct scanctrl_s scanctrl_buffer;
748
scanctrl_t scanctrl = &scanctrl_buffer;
749
tar_header_t hdr, *start_tail;
750
estream_t outstream = NULL;
753
#ifdef HAVE_DOSISH_SYSTEM
755
setmode (es_fileno (es_stdin), O_BINARY);
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 ();
856
log_error (_("can't create `%s': %s\n"),
857
opt.outfile, gpg_strerror (err));
863
outstream = es_stdout;
866
#ifdef HAVE_DOSISH_SYSTEM
867
if (outstream == es_stdout)
868
setmode (es_fileno (es_stdout), O_BINARY);
871
for (hdr = scanctrl->flist; hdr; hdr = hdr->next)
873
err = write_file (outstream, hdr);
877
err = write_eof_mark (outstream);
882
if (outstream != es_stdout)
883
err = es_fclose (outstream);
885
err = es_fflush (outstream);
890
log_error ("creating tarball `%s' failed: %s\n",
891
es_fname_get (outstream), gpg_strerror (err));
892
if (outstream && outstream != es_stdout)
893
es_fclose (outstream);
895
remove (opt.outfile);
897
scanctrl->flist_tail = NULL;
898
while ( (hdr = scanctrl->flist) )
900
scanctrl->flist = hdr->next;