LCOV - code coverage report
Current view: top level - util/archive - fd_tar.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 61 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 54 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_util_archive_fd_tar_h
       2             : #define HEADER_fd_src_util_archive_fd_tar_h
       3             : 
       4             : /* fd_tar implements the ustar and old-GNU versions of the TAR file
       5             :    format. This is not a general-purpose TAR implementation.  It is
       6             :    currently only intended for loading and writing Solana snapshots. */
       7             : 
       8             : #include "../bits/fd_bits.h"
       9             : #include "../cstr/fd_cstr.h"
      10             : 
      11             : /* File Format ********************************************************/
      12             : 
      13             : /* The high level format of a tar archive/ball is a set of 512 byte blocks.
      14             :    Each file will be described a tar header (fd_tar_meta_t) and will be
      15             :    followed by the raw bytes of the file. The last block that is used for
      16             :    the file will be padded to fit into a tar block. When the archive is
      17             :    completed, it will be trailed by two EOF blocks which are populated with
      18             :    zero bytes. */
      19             : 
      20             : /* fd_tar_meta_t is the ustar/OLDGNU version of the TAR header. */
      21             : 
      22           0 : #define FD_TAR_BLOCK_SZ (512UL)
      23             : 
      24             : struct __attribute__((packed)) fd_tar_meta {
      25           0 : # define FD_TAR_NAME_SZ 100
      26             : # define FD_TAR_SIZE_SZ 12
      27             :   /* 0x000 */ char name    [ FD_TAR_NAME_SZ ];
      28             :   /* 0x064 */ char mode    [   8 ];
      29             :   /* 0x06c */ char uid     [   8 ];
      30             :   /* 0x074 */ char gid     [   8 ];
      31             :   /* 0x07c */ char size    [  12 ];
      32             :   /* 0x088 */ char mtime   [  12 ];
      33             :   /* 0x094 */ char chksum  [   8 ];
      34             :   /* 0x09c */ char typeflag;
      35             :   /* 0x09d */ char linkname[ 100 ];
      36             : # define FD_TAR_MAGIC_SZ 5
      37             :   /* 0x101 */ char magic   [ FD_TAR_MAGIC_SZ+1 ];
      38             :   /* 0x107 */ char version [   2 ];
      39             :   /* 0x109 */ char uname   [  32 ];
      40             :   /* 0x129 */ char gname   [  32 ];
      41             :   /* 0x149 */ char devmajor[   8 ];
      42             :   /* 0x151 */ char devminor[   8 ];
      43             :   /* 0x159 */ char prefix  [ 155 ];
      44             :   /* 0x1f4 */ char padding [  12 ];
      45             : };
      46             : 
      47             : typedef struct fd_tar_meta fd_tar_meta_t;
      48             : 
      49             : /* FD_TAR_MAGIC is the only value of fd_tar_meta::magic supported by
      50             :    fd_tar. */
      51             : 
      52           0 : #define FD_TAR_MAGIC "ustar"
      53             : 
      54             : /* Known file types */
      55             : 
      56           0 : #define FD_TAR_TYPE_NULL      ('\0')  /* implies FD_TAR_TYPE_REGULAR */
      57           0 : #define FD_TAR_TYPE_REGULAR   ('0')
      58             : #define FD_TAR_TYPE_HARD_LINK ('1')
      59             : #define FD_TAR_TYPE_SYM_LINK  ('2')
      60             : #define FD_TAR_TYPE_CHAR_DEV  ('3')
      61             : #define FD_TAR_TYPE_BLOCK_DEV ('4')
      62             : #define FD_TAR_TYPE_DIR       ('5')
      63             : #define FD_TAR_TYPE_FIFO      ('6')
      64             : 
      65             : FD_PROTOTYPES_BEGIN
      66             : 
      67             : /* fd_tar_meta_is_reg returns 1 if the file type is 'regular', and 0
      68             :    otherwise. */
      69             : 
      70             : FD_FN_PURE static inline int
      71           0 : fd_tar_meta_is_reg( fd_tar_meta_t const * meta ) {
      72           0 :   return ( meta->typeflag == FD_TAR_TYPE_NULL    )
      73           0 :        | ( meta->typeflag == FD_TAR_TYPE_REGULAR );
      74           0 : }
      75             : 
      76             : /* fd_tar_meta_get_size parses the size field of the TAR header.
      77             :    Returns ULONG_MAX if parsing failed. */
      78             : 
      79             : FD_FN_PURE FD_FN_UNUSED static ulong
      80           0 : fd_tar_meta_get_size( fd_tar_meta_t const * meta ) {
      81           0 :   char const * buf = meta->size;
      82           0 :   if( ((uchar)buf[0]) & 0x80U ) {
      83             :     /* OLDGNU tar files may use a binary size encoding */
      84           0 :     return fd_ulong_bswap( FD_LOAD( ulong, buf+4 ) );
      85           0 :   }
      86             : 
      87           0 :   ulong ret = 0UL;
      88           0 :   for( char const * p=buf; p<buf+12; p++ ) {
      89           0 :     if( *p == '\0' ) break;
      90           0 :     ret = (ret << 3) + (ulong)(*p - '0');
      91           0 :   }
      92             : 
      93           0 :   return ret;
      94           0 : }
      95             : 
      96             : /* fd_tar_set_octal is a helper function to write octal fields per TAR
      97             :    standard.  Each field of width buf_sz contains buf_sz-1 zero-filled
      98             :    octal digits and a null terminator.  Returns 1 on success, 0 if val
      99             :    is too large to be represented in the field. */
     100             : static inline int
     101             : fd_tar_set_octal( char * buf,
     102             :                   ulong  buf_sz,
     103           0 :                   ulong  val ) {
     104             :   /* Need at least 1 byte for null terminator */
     105           0 :   if( FD_UNLIKELY( buf_sz < 1 ) ) return 0;
     106             : 
     107             :   /* Check if val fits in buf_sz-1 octal digits */
     108           0 :   if( FD_UNLIKELY( val >> (3UL*(buf_sz-1UL)) ) ) return 0;
     109             : 
     110           0 :   memset( buf, '0', buf_sz-1UL );
     111           0 :   buf[ buf_sz-1UL ] = '\0';
     112             : 
     113           0 :   for( ulong i=buf_sz-1UL; i>0UL && val>0UL; i-- ) {
     114           0 :     buf[ i-1UL ] = '0' + (val&7UL);  /* Extract low 3 bits as octal digit */
     115           0 :     val >>= 3;                       /* Divide by 8 */
     116           0 :   }
     117             : 
     118           0 :   return 1;
     119           0 : }
     120             : 
     121             : /* fd_tar_meta_set_size sets the size field.  Returns 1 on success, 0
     122             :    if sz is too large to be represented in TAR header. */
     123             : 
     124             : static inline int
     125             : fd_tar_meta_set_size( fd_tar_meta_t * meta,
     126           0 :                       ulong           sz ) {
     127           0 :   return fd_tar_set_octal( meta->size, sizeof(meta->size), sz );
     128           0 : }
     129             : 
     130             : /* fd_tar_meta_set_mtime sets the modification time field.  Returns 1
     131             :    on success, 0 if mtime cannot be represented in TAR header. */
     132             : 
     133             : static inline int
     134             : fd_tar_meta_set_mtime( fd_tar_meta_t * meta,
     135           0 :                        ulong           mtime ) {
     136           0 :   return fd_tar_set_octal( meta->mtime, sizeof(meta->mtime), mtime );
     137           0 : }
     138             : 
     139             : static inline int
     140             : fd_tar_meta_init_file_default( fd_tar_meta_t * meta,
     141             :                                char const *    filename,
     142             :                                ulong           filesize,
     143           0 :                                long            now ) {
     144           0 :   int valid = 1;
     145           0 :   memset( meta, 0, sizeof(fd_tar_meta_t) );
     146           0 :   valid &= fd_cstr_printf_check( meta->name, sizeof(meta->name), NULL, "%s", filename );
     147           0 :   valid &= fd_cstr_printf_check( meta->mode, sizeof(meta->mode), NULL, "0000644" );
     148           0 :   valid &= fd_cstr_printf_check( meta->uid,  sizeof(meta->uid),  NULL, "0000000" );
     149           0 :   valid &= fd_cstr_printf_check( meta->gid,  sizeof(meta->gid),  NULL, "0000000" );
     150           0 :   valid &= fd_tar_meta_set_size( meta, filesize );
     151           0 :   valid &= fd_tar_meta_set_mtime( meta, (ulong)(now/1000000000L));
     152           0 :   valid &= fd_cstr_printf_check( meta->magic, sizeof(meta->magic), NULL, FD_TAR_MAGIC );
     153           0 :   valid &= fd_cstr_printf_check( meta->uname, sizeof(meta->uname), NULL, "root" );
     154           0 :   valid &= fd_cstr_printf_check( meta->gname, sizeof(meta->gname), NULL, "root" );
     155           0 :   valid &= fd_cstr_printf_check( meta->devmajor, sizeof(meta->devmajor), NULL, "0000000" );
     156           0 :   valid &= fd_cstr_printf_check( meta->devminor, sizeof(meta->devminor), NULL, "0000000" );
     157           0 :   meta->typeflag = FD_TAR_TYPE_REGULAR;
     158           0 :   meta->version[ 0 ] = '0'; meta->version[ 1 ] = '0';
     159             :   /* meta->linkname empty */
     160             :   /* meta->prefix empty. TODO: add support */
     161             : 
     162           0 :   ulong checksum = 0;
     163             : 
     164           0 :   for( ulong i=0UL; i<FD_TAR_BLOCK_SZ; i++ ) {
     165             :     /* Special handling for the checksum field itself
     166             :         148UL==offsetof(meta->chksum)
     167             :         156UL==offsetof(meta->chksum)+sizeof(meta->chksum)
     168             :     */
     169           0 :     checksum += (i>=148UL && i<156UL) ? 32UL : ((uchar *)meta)[ i ];
     170           0 :   }
     171             : 
     172           0 :   valid &= fd_tar_set_octal( meta->chksum, sizeof(meta->chksum), checksum );
     173             : 
     174           0 :   return valid;
     175           0 : }
     176             : 
     177             : FD_PROTOTYPES_END
     178             : 
     179             : #endif /* HEADER_fd_src_util_archive_fd_tar_h */

Generated by: LCOV version 1.14