LCOV - code coverage report
Current view: top level - tools - gpgtar-list.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 146 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /* gpgtar-list.c - List 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 <assert.h>
      26             : 
      27             : #include "i18n.h"
      28             : #include "gpgtar.h"
      29             : 
      30             : 
      31             : 
      32             : static unsigned long long
      33           0 : parse_xoctal (const void *data, size_t length, const char *filename)
      34             : {
      35           0 :   const unsigned char *p = data;
      36             :   unsigned long long value;
      37             : 
      38           0 :   if (!length)
      39           0 :     value = 0;
      40           0 :   else if ( (*p & 0x80))
      41             :     {
      42             :       /* Binary format.  */
      43           0 :       value = (*p++ & 0x7f);
      44           0 :       while (--length)
      45             :         {
      46           0 :           value <<= 8;
      47           0 :           value |= *p++;
      48             :         }
      49             :     }
      50             :   else
      51             :     {
      52             :       /* Octal format  */
      53           0 :       value = 0;
      54             :       /* Skip leading spaces and zeroes.  */
      55           0 :       for (; length && (*p == ' ' || *p == '0'); length--, p++)
      56             :         ;
      57           0 :       for (; length && *p; length--, p++)
      58             :         {
      59           0 :           if (*p >= '0' && *p <= '7')
      60             :             {
      61           0 :               value <<= 3;
      62           0 :               value += (*p - '0');
      63             :             }
      64             :           else
      65             :             {
      66           0 :               log_error ("%s: invalid octal number encountered - assuming 0\n", 
      67             :                          filename);
      68           0 :               value = 0;
      69           0 :               break;
      70             :             }
      71             :         }
      72             :     }
      73           0 :   return value;
      74             : }
      75             : 
      76             : 
      77             : static tar_header_t
      78           0 : parse_header (const void *record, const char *filename)
      79             : {
      80           0 :   const struct ustar_raw_header *raw = record;
      81             :   size_t n, namelen, prefixlen;
      82             :   tar_header_t header;
      83             :   int use_prefix;
      84             : 
      85           0 :   use_prefix = (!memcmp (raw->magic, "ustar", 5) 
      86           0 :                 && (raw->magic[5] == ' ' || !raw->magic[5]));
      87             : 
      88             : 
      89           0 :   for (namelen=0; namelen < sizeof raw->name && raw->name[namelen]; namelen++)
      90             :     ;
      91           0 :   if (namelen == sizeof raw->name)
      92           0 :     log_info ("%s: warning: name not terminated by a nul byte\n", filename);
      93           0 :   for (n=namelen+1; n < sizeof raw->name; n++)
      94           0 :     if (raw->name[n])
      95             :       {
      96           0 :         log_info ("%s: warning: garbage after name\n", filename);
      97           0 :         break;
      98             :       }
      99             : 
     100             : 
     101           0 :   if (use_prefix && raw->prefix[0])
     102             :     {
     103           0 :       for (prefixlen=0; (prefixlen < sizeof raw->prefix
     104           0 :                          && raw->prefix[prefixlen]); prefixlen++)
     105             :         ;
     106           0 :       if (prefixlen == sizeof raw->prefix)
     107           0 :         log_info ("%s: warning: prefix not terminated by a nul byte\n",
     108             :                   filename);
     109           0 :       for (n=prefixlen+1; n < sizeof raw->prefix; n++)
     110           0 :         if (raw->prefix[n])
     111             :           {
     112           0 :             log_info ("%s: warning: garbage after prefix\n", filename);
     113           0 :             break;
     114             :           }
     115             :     }
     116             :   else
     117           0 :     prefixlen = 0;
     118             : 
     119           0 :   header = xtrycalloc (1, sizeof *header + prefixlen + 1 + namelen);
     120           0 :   if (!header)
     121             :     {
     122           0 :       log_error ("%s: error allocating header: %s\n",
     123             :                  filename, gpg_strerror (gpg_error_from_syserror ()));
     124           0 :       return NULL;
     125             :     }
     126           0 :   if (prefixlen)
     127             :     {
     128           0 :       n = prefixlen;
     129           0 :       memcpy (header->name, raw->prefix, n);
     130           0 :       if (raw->prefix[n-1] != '/')
     131           0 :         header->name[n++] = '/';
     132             :     }
     133             :   else
     134           0 :     n = 0;
     135           0 :   memcpy (header->name+n, raw->name, namelen);
     136           0 :   header->name[n+namelen] = 0;
     137             :   
     138           0 :   header->mode  = parse_xoctal (raw->mode, sizeof raw->mode, filename);
     139           0 :   header->uid   = parse_xoctal (raw->uid, sizeof raw->uid, filename);
     140           0 :   header->gid   = parse_xoctal (raw->gid, sizeof raw->gid, filename);
     141           0 :   header->size  = parse_xoctal (raw->size, sizeof raw->size, filename);
     142           0 :   header->mtime = parse_xoctal (raw->mtime, sizeof raw->mtime, filename);
     143             :   /* checksum = */
     144           0 :   switch (raw->typeflag[0])
     145             :     {
     146           0 :     case '0': header->typeflag = TF_REGULAR; break;
     147           0 :     case '1': header->typeflag = TF_HARDLINK; break;
     148           0 :     case '2': header->typeflag = TF_SYMLINK; break;
     149           0 :     case '3': header->typeflag = TF_CHARDEV; break;
     150           0 :     case '4': header->typeflag = TF_BLOCKDEV; break;
     151           0 :     case '5': header->typeflag = TF_DIRECTORY; break;
     152           0 :     case '6': header->typeflag = TF_FIFO; break;
     153           0 :     case '7': header->typeflag = TF_RESERVED; break;
     154           0 :     default:  header->typeflag = TF_UNKNOWN; break;
     155             :     }
     156             : 
     157             : 
     158             :   /* Compute the number of data records following this header.  */
     159           0 :   if (header->typeflag == TF_REGULAR || header->typeflag == TF_UNKNOWN)
     160           0 :     header->nrecords = (header->size + RECORDSIZE-1)/RECORDSIZE;
     161             :   else
     162           0 :     header->nrecords = 0;
     163             :   
     164             : 
     165           0 :   return header;
     166             : }
     167             : 
     168             : 
     169             : 
     170             : /* Read the next block, assming it is a tar header.  Returns a header
     171             :    object on success or NULL one error.  In case of an error an error
     172             :    message has been printed.  */
     173             : static tar_header_t
     174           0 : read_header (estream_t stream)
     175             : {
     176             :   gpg_error_t err;
     177             :   char record[RECORDSIZE];
     178             :   int i;
     179             : 
     180           0 :   err = read_record (stream, record);
     181           0 :   if (err)
     182           0 :     return NULL;
     183             : 
     184           0 :   for (i=0; i < RECORDSIZE && !record[i]; i++)
     185             :     ;
     186           0 :   if (i == RECORDSIZE)
     187             :     {
     188             :       /* All zero header - check whether it is the first part of an
     189             :          end of archive mark.  */
     190           0 :       err = read_record (stream, record);
     191           0 :       if (err)
     192           0 :         return NULL;
     193             :       
     194           0 :       for (i=0; i < RECORDSIZE && !record[i]; i++)
     195             :         ;
     196           0 :       if (i != RECORDSIZE)
     197           0 :         log_info ("%s: warning: skipping empty header\n",
     198             :                   es_fname_get (stream));
     199             :       else
     200             :         {
     201             :           /* End of archive - FIXME: we might want to check for garbage.  */
     202           0 :           return NULL;
     203             :         }
     204             :     }
     205             : 
     206           0 :   return parse_header (record, es_fname_get (stream));
     207             : }
     208             : 
     209             : 
     210             : /* Skip the data records according to HEADER.  Prints an error message
     211             :    on error and return -1. */
     212             : static int
     213           0 : skip_data (estream_t stream, tar_header_t header)
     214             : {
     215             :   char record[RECORDSIZE];
     216             :   unsigned long long n;
     217             : 
     218           0 :   for (n=0; n < header->nrecords; n++)
     219             :     {
     220           0 :       if (read_record (stream, record))
     221           0 :         return -1;
     222             :     }
     223             : 
     224           0 :   return 0;
     225             : }
     226             : 
     227             : 
     228             : 
     229             : static void
     230           0 : print_header (tar_header_t header, estream_t out)
     231             : {
     232             :   unsigned long mask;
     233             :   char modestr[10+1];
     234             :   int i;
     235             : 
     236           0 :   *modestr = '?';
     237           0 :   switch (header->typeflag)
     238             :     {
     239           0 :     case TF_REGULAR:  *modestr = '-'; break;
     240           0 :     case TF_HARDLINK: *modestr = 'h'; break;
     241           0 :     case TF_SYMLINK:  *modestr = 'l'; break;
     242           0 :     case TF_CHARDEV:  *modestr = 'c'; break;
     243           0 :     case TF_BLOCKDEV: *modestr = 'b'; break;
     244           0 :     case TF_DIRECTORY:*modestr = 'd'; break;
     245           0 :     case TF_FIFO:     *modestr = 'f'; break;
     246           0 :     case TF_RESERVED: *modestr = '='; break;
     247           0 :     case TF_UNKNOWN:  break;
     248           0 :     case TF_NOTSUP:   break;
     249             :     }
     250           0 :   for (mask = 0400, i = 0; i < 9; i++, mask >>= 1)
     251           0 :     modestr[1+i] = (header->mode & mask)? "rwxrwxrwx"[i]:'-';
     252           0 :   if ((header->typeflag & 04000))
     253           0 :     modestr[3] = modestr[3] == 'x'? 's':'S';
     254           0 :   if ((header->typeflag & 02000))
     255           0 :     modestr[6] = modestr[6] == 'x'? 's':'S';
     256           0 :   if ((header->typeflag & 01000))
     257           0 :     modestr[9] = modestr[9] == 'x'? 't':'T';
     258           0 :   modestr[10] = 0;
     259             : 
     260           0 :   es_fprintf (out, "%s %lu %lu/%lu %12llu %s %s\n",
     261             :               modestr, header->nlink, header->uid, header->gid, header->size,
     262           0 :               isotimestamp (header->mtime), header->name);
     263           0 : }
     264             : 
     265             : 
     266             : 
     267             : /* List the tarball FILENAME or, if FILENAME is NULL, the tarball read
     268             :    from stdin.  */
     269             : void
     270           0 : gpgtar_list (const char *filename)
     271             : {
     272             :   gpg_error_t err;
     273             :   estream_t stream;
     274             :   tar_header_t header;
     275             : 
     276           0 :   if (filename)
     277             :     {
     278           0 :       if (!strcmp (filename, "-"))
     279           0 :         stream = es_stdout;
     280             :       else
     281           0 :         stream = es_fopen (filename, "rb");
     282           0 :       if (!stream)
     283             :         {
     284           0 :           err = gpg_error_from_syserror ();
     285           0 :           log_error ("error opening '%s': %s\n", filename, gpg_strerror (err));
     286           0 :           return;
     287             :         }
     288             :     }
     289             :   else
     290           0 :     stream = es_stdin;
     291             : 
     292           0 :   if (stream == es_stdin)
     293           0 :     es_set_binary (es_stdin);
     294             : 
     295             :   for (;;)
     296             :     {
     297           0 :       header = read_header (stream);
     298           0 :       if (!header)
     299           0 :         goto leave;
     300             :       
     301           0 :       print_header (header, es_stdout);
     302             :       
     303           0 :       if (skip_data (stream, header))
     304           0 :         goto leave;
     305           0 :       xfree (header);
     306           0 :       header = NULL;
     307           0 :     }
     308             : 
     309             : 
     310             :  leave:
     311           0 :   xfree (header);
     312           0 :   if (stream != es_stdin)
     313           0 :     es_fclose (stream);
     314           0 :   return;
     315             : }
     316             : 
     317             : tar_header_t
     318           0 : gpgtar_read_header (estream_t stream)
     319             : {
     320             :   /*FIXME: Change to return an error code.  */
     321           0 :   return read_header (stream);
     322             : }
     323             : 
     324             : void
     325           0 : gpgtar_print_header (tar_header_t header, estream_t out)
     326             : {
     327           0 :   if (header && out)
     328           0 :     print_header (header, out);
     329           0 : }

Generated by: LCOV version 1.11