LCOV - code coverage report
Current view: top level - util/archive - fd_tar.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 6 116 5.2 %
Date: 2024-11-13 11:58:15 Functions: 1 8 12.5 %

          Line data    Source code
       1             : #include "fd_tar.h"
       2             : #include "../fd_util.h"
       3             : 
       4             : #include <errno.h>
       5             : 
       6             : fd_tar_reader_t *
       7             : fd_tar_reader_new( void *                       mem,
       8             :                    fd_tar_read_vtable_t const * cb_vt,
       9           0 :                    void *                       cb_arg ) {
      10             : 
      11           0 :   if( FD_UNLIKELY( !mem ) ) {
      12           0 :     FD_LOG_WARNING(( "NULL mem" ));
      13           0 :     return NULL;
      14           0 :   }
      15           0 :   if( FD_UNLIKELY( !cb_vt || !cb_vt->file || !cb_vt->read ) ) {
      16           0 :     FD_LOG_WARNING(( "NULL callback" ));
      17           0 :     return NULL;
      18           0 :   }
      19           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_tar_reader_align() ) ) ) {
      20           0 :     FD_LOG_WARNING(( "unaligned mem" ));
      21           0 :     return NULL;
      22           0 :   }
      23             : 
      24           0 :   fd_tar_reader_t * self = (fd_tar_reader_t *)mem;
      25           0 :   fd_memset( self, 0, sizeof(fd_tar_reader_t) );
      26           0 :   self->cb_vt  = *cb_vt;
      27           0 :   self->cb_arg = cb_arg;
      28           0 :   return self;
      29           0 : }
      30             : 
      31             : void *
      32           0 : fd_tar_reader_delete( fd_tar_reader_t * reader ) {
      33           0 :   if( FD_UNLIKELY( !reader ) ) return NULL;
      34           0 :   fd_memset( reader, 0, sizeof(fd_tar_reader_t) );
      35           0 :   return reader;
      36           0 : }
      37             : 
      38             : static int
      39           0 : fd_tar_process_hdr( fd_tar_reader_t * reader ) {
      40             : 
      41           0 :   fd_tar_meta_t const * hdr = (fd_tar_meta_t const *)reader->buf;
      42             : 
      43             :   /* "ustar\x00" and "ustar  \x00" (overlaps with version) are both
      44             :      valid values for magic.  These are POSIX ustar and OLDGNU versions
      45             :      respectively. */
      46           0 :   if( FD_UNLIKELY( 0!=memcmp( hdr->magic, FD_TAR_MAGIC, 5UL ) ) ) {
      47             : 
      48             :     /* Detect EOF.  A TAR EOF is marked by 1024 bytes of zeros.
      49             :        We abort after 512 bytes. */
      50           0 :     int not_zero=0;
      51           0 :     for( ulong i=0UL; i<sizeof(fd_tar_meta_t); i++ )
      52           0 :       not_zero |= reader->buf[ i ];
      53           0 :     if( !not_zero ) return -1;
      54             : 
      55             :     /* Not an EOF, so must be a protocol error */
      56           0 :     FD_LOG_WARNING(( "Invalid tar header magic at %#lx", reader->pos ));
      57           0 :     FD_LOG_HEXDUMP_WARNING(( "Tar header", hdr, sizeof(fd_tar_meta_t) ));
      58           0 :     return EPROTO;
      59           0 :   }
      60             : 
      61           0 :   ulong file_sz = fd_tar_meta_get_size( &reader->header );
      62           0 :   if( FD_UNLIKELY( file_sz==ULONG_MAX ) ) {
      63           0 :     FD_LOG_WARNING(( "Failed to parse file size in tar header" ));
      64           0 :     return EPROTO;
      65           0 :   }
      66           0 :   reader->file_sz = file_sz;
      67           0 :   reader->buf_ctr = (ushort)0U;
      68             : 
      69             :   /* Ensure name is terminated */
      70           0 :   reader->header.name[ FD_TAR_NAME_SZ-1 ] = '\0';
      71             : 
      72             :   /* Call back to recipient */
      73           0 :   int err = reader->cb_vt.file( reader->cb_arg, &reader->header, file_sz );
      74           0 :   return fd_int_if( err, EIO, 0 );
      75           0 : }
      76             : 
      77             : static int
      78             : fd_tar_read_hdr( fd_tar_reader_t * reader,
      79             :                  uchar const **    pcur,
      80           0 :                  uchar const *     end ) {
      81             : 
      82           0 :   uchar const * cur = *pcur;
      83             : 
      84             :   /* Skip padding */
      85           0 :   if( reader->buf_ctr==0UL ) {
      86           0 :     ulong  pad_sz = fd_ulong_align_up( reader->pos, 512UL ) - reader->pos;
      87           0 :            pad_sz = fd_ulong_min( pad_sz, (ulong)( end-cur ) );
      88           0 :     cur += pad_sz;
      89           0 :   }
      90             : 
      91             :   /* Determine number of bytes to read */
      92           0 :   long chunk_sz = (long)sizeof(fd_tar_meta_t) - (long)reader->buf_ctr;
      93           0 :   FD_TEST( chunk_sz>=0L );
      94           0 :   if( end-cur < chunk_sz ) chunk_sz = end-cur;
      95             : 
      96             :   /* Copy to header */
      97           0 :   fd_memcpy( reader->buf + reader->buf_ctr, cur, (ulong)chunk_sz );
      98           0 :   cur             +=        chunk_sz;
      99           0 :   reader->buf_ctr += (ulong)chunk_sz;
     100             : 
     101             :   /* Handle complete header */
     102           0 :   int ret = 0;
     103           0 :   if( reader->buf_ctr == sizeof(fd_tar_meta_t) )
     104           0 :     ret = fd_tar_process_hdr( reader );
     105             : 
     106           0 :   *pcur = cur;
     107           0 :   return ret;
     108           0 : }
     109             : 
     110             : static int
     111             : fd_tar_read_data( fd_tar_reader_t * reader,
     112             :                   uchar const **    pcur,
     113           0 :                   uchar const *     end ) {
     114             : 
     115           0 :   uchar const * cur = *pcur;
     116           0 :   FD_TEST( cur<=end );
     117             : 
     118             :   /* Determine number of bytes to read */
     119           0 :   ulong chunk_sz = reader->file_sz;
     120           0 :   ulong avail_sz = (ulong)( end-cur );
     121           0 :   if( avail_sz < chunk_sz ) chunk_sz = avail_sz;
     122             : 
     123             :   /* Call back to recipient */
     124           0 :   int err = reader->cb_vt.read( reader->cb_arg, cur, chunk_sz );
     125             : 
     126             :   /* Consume bytes */
     127           0 :   cur             += chunk_sz;
     128           0 :   reader->file_sz -= chunk_sz;
     129             : 
     130           0 :   *pcur = cur;
     131           0 :   return fd_int_if( err, EIO, 0 );
     132           0 : }
     133             : 
     134             : int
     135             : fd_tar_read( void *        const reader_,
     136             :              uchar const * const data,
     137           0 :              ulong         const data_sz ) {
     138             : 
     139           0 :   fd_tar_reader_t * reader = reader_;
     140           0 :   ulong const pos = reader->pos;
     141             : 
     142           0 :   uchar const * cur = data;
     143           0 :   uchar const * end = cur+data_sz;
     144             : 
     145           0 :   while( cur!=end ) {
     146           0 :     if( reader->file_sz ) {
     147           0 :       int err = fd_tar_read_data( reader, &cur, end );
     148           0 :       if( FD_UNLIKELY( !!err ) ) return err;
     149           0 :       reader->pos = pos + (ulong)( cur-data );
     150           0 :     }
     151           0 :     if( !reader->file_sz ) {
     152           0 :       int err = fd_tar_read_hdr( reader, &cur, end );
     153           0 :       if( FD_UNLIKELY( !!err ) ) return err;
     154           0 :       reader->pos = pos + (ulong)( cur-data );
     155           0 :     }
     156           0 :   }
     157             : 
     158           0 :   return 0;
     159           0 : }
     160             : 
     161             : FD_FN_PURE ulong
     162           3 : fd_tar_meta_get_size( fd_tar_meta_t const * meta ) {
     163           3 :   char const * buf = meta->size;
     164           3 :   if( ((uchar)buf[0]) & 0x80U ) {
     165             :     /* OLDGNU tar files may use a binary size encoding */
     166           3 :     return fd_ulong_bswap( FD_LOAD( ulong, buf+4 ) );
     167           3 :   }
     168             : 
     169           0 :   ulong ret = 0UL;
     170           0 :   for( char const * p=buf; p<buf+12; p++ ) {
     171           0 :     if( *p == '\0' ) break;
     172           0 :     ret = (ret << 3) + (ulong)(*p - '0');
     173           0 :   }
     174             : 
     175           0 :   return ret;
     176           3 : }
     177             : 
     178             : int
     179             : fd_tar_set_octal( char  buf[ static 12 ],
     180           0 :                   ulong val ) {
     181           0 :   buf[ 11 ] = '\0';
     182           0 :   for( int i=10; i>=0; i-- ) {
     183           0 :     buf[ i ] = (char)( '0' + (char)( val&7UL ) );
     184           0 :     val>>=3;
     185           0 :   }
     186           0 :   return val==0UL;
     187           0 : }

Generated by: LCOV version 1.14