~ubuntu-branches/ubuntu/quantal/gnupg2/quantal-proposed

« back to all changes in this revision

Viewing changes to tools/gpgtar-create.c

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-05-25 14:27:35 UTC
  • mfrom: (1.1.15 upstream) (7.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20110525142735-jccyw0fopnyv728q
Tags: 2.0.17-2ubuntu1
* Merge from debian unstable. Remaining changes:
  - Add udev rules to give gpg access to some smartcard readers;
    Debian #543217.
    . debian/gnupg2.dev: udev rules to set ACLs on SCM smartcard readers.
    . debian/rules: Call dh_installudev.
  - debian/control: Rename Vcs-* to XS-Debian-Vcs-*.

Show diffs side-by-side

added added

removed removed

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