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

Generated by: LCOV version 1.11