LCOV - code coverage report
Current view: top level - tools - gpgtar-create.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 252 396 63.6 %
Date: 2016-11-29 15:00:56 Functions: 12 12 100.0 %

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

Generated by: LCOV version 1.11