LCOV - code coverage report
Current view: top level - util/checkpt - fd_restore.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 382 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 10 0.0 %

          Line data    Source code
       1             : #include "fd_checkpt.h"
       2             : 
       3             : #if FD_HAS_LZ4
       4             : #include <lz4.h>
       5             : 
       6             : /* fd_restore_private_lz4 decompresses the cbuf_max memory region
       7             :    pointed to by cbuf into the ubuf_usz memory region pointed to by ubuf
       8             :    using the given lz4 decompressor.  Assumes lz4, ubuf and cbuf are
       9             :    valid and assumes ubuf_usz matches the corresponding
      10             :    fd_checkpt_private_lz4 call and cbuf is valid.  On success, returns
      11             :    the number of leading bytes cbuf bytes that were used for the
      12             :    decompression (will be in [4,cbuf_max]) and the ubuf should not
      13             :    be modified until the stream is reset, closed or an additional 64 KiB
      14             :    has been decompressed.  On failure, returns 0 and retains no interest
      15             :    in ubuf.  In either case, this retains no interest in cbuf on return.
      16             : 
      17             :    _sbuf, sbuf_sz, sbuf_thresh, _sbuf_cursor specify the small buf
      18             :    scatter ring state.  See fd_checkpt_private_lz4 for more details. */
      19             : 
      20             : static ulong
      21             : fd_restore_private_lz4( LZ4_streamDecode_t * lz4,
      22             :                         void *               _ubuf,
      23             :                         ulong                ubuf_usz,
      24             :                         void const *         _cbuf,
      25             :                         ulong                cbuf_max,
      26             :                         void *               _sbuf,
      27             :                         ulong                sbuf_sz,
      28             :                         ulong                sbuf_thresh,
      29           0 :                         ulong *              _sbuf_cursor ) {
      30           0 :   char *       ubuf = (char *)      _ubuf;
      31           0 :   char const * cbuf = (char const *)_cbuf;
      32             : 
      33             :   /* Verify ubuf_usz is in [1,LZ4_MAX_INPUT_SIZE] and cbuf_max is large
      34             :      enough to store a header and a non-trivial compressed body. */
      35             : 
      36           0 :   if( FD_UNLIKELY( !((1UL<=ubuf_usz) & (ubuf_usz<=(ulong)LZ4_MAX_INPUT_SIZE)) ) ) {
      37           0 :     FD_LOG_WARNING(( "bad ubuf_usz" ));
      38           0 :     return 0UL;
      39           0 :   }
      40             : 
      41           0 :   if( FD_UNLIKELY( cbuf_max<4UL ) ) { /* 3 bytes for header, 1 byte minimum for body */
      42           0 :     FD_LOG_WARNING(( "truncated header" ));
      43           0 :     return 0UL;
      44           0 :   }
      45             : 
      46             :   /* Restore and validate header */
      47             : 
      48           0 :   ulong ubuf_csz = (((ulong)(uchar)cbuf[0])      )
      49           0 :                  | (((ulong)(uchar)cbuf[1]) <<  8)
      50           0 :                  | (((ulong)(uchar)cbuf[2]) << 16); /* In [1,2^24) */
      51             : 
      52           0 :   ulong cbuf_sz  = ubuf_csz + 3UL;
      53           0 :   if( FD_UNLIKELY( !((4UL<=cbuf_sz) & (cbuf_sz<=FD_CHECKPT_PRIVATE_CSZ_MAX( ubuf_usz ))) ) ) {
      54           0 :     FD_LOG_WARNING(( "corrupt header" ));
      55           0 :     return 0UL;
      56           0 :   }
      57             : 
      58           0 :   if( FD_UNLIKELY( cbuf_sz>cbuf_max ) ) {
      59           0 :     FD_LOG_WARNING(( "truncated checkpt" ));
      60           0 :     return 0UL;
      61           0 :   }
      62             : 
      63             :   /* Small ubuf scatter optimization.  See note in
      64             :      fd_checkpt_private_lz4 for details. */
      65             : 
      66           0 :   int is_small = ubuf_usz<=sbuf_thresh;
      67           0 :   if( is_small ) { /* app dependent branch prob */
      68           0 :     ulong sbuf_cursor = *_sbuf_cursor;
      69           0 :     if( (sbuf_sz-sbuf_cursor)<ubuf_usz ) sbuf_cursor = 0UL; /* cmov */
      70           0 :     ubuf = (char *)_sbuf + sbuf_cursor;
      71           0 :     *_sbuf_cursor = sbuf_cursor + ubuf_usz;
      72           0 :   }
      73             : 
      74             :   /* Restore the buffer */
      75             : 
      76           0 :   int res = LZ4_decompress_safe_continue( lz4, cbuf+3UL, ubuf, (int)ubuf_csz, (int)ubuf_usz );
      77           0 :   if( FD_UNLIKELY( res<=0 ) ) {
      78           0 :     FD_LOG_WARNING(( "LZ4_decompress_safe_continue error (%i)", res ));
      79           0 :     return 0UL;
      80           0 :   }
      81             : 
      82             :   /* Small ubuf scatter optimization */
      83             : 
      84           0 :   if( is_small ) memcpy( _ubuf, ubuf, ubuf_usz ); /* app dependent branch prob */
      85             : 
      86           0 :   return cbuf_sz;
      87           0 : }
      88             : #endif
      89             : 
      90             : fd_restore_t *
      91             : fd_restore_init_stream( void * mem,
      92             :                         int    fd,
      93             :                         void * rbuf,
      94           0 :                         ulong  rbuf_sz ) {
      95             : 
      96             :   /* Check input args */
      97             : 
      98           0 :   if( FD_UNLIKELY( !mem ) ) {
      99           0 :     FD_LOG_WARNING(( "NULL mem" ));
     100           0 :     return NULL;
     101           0 :   }
     102             : 
     103           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_RESTORE_ALIGN ) ) ) {
     104           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     105           0 :     return NULL;
     106           0 :   }
     107             : 
     108           0 :   if( FD_UNLIKELY( fd<0 ) ) {
     109           0 :     FD_LOG_WARNING(( "bad fd" ));
     110           0 :     return NULL;
     111           0 :   }
     112             : 
     113           0 :   if( FD_UNLIKELY( !rbuf ) ) {
     114           0 :     FD_LOG_WARNING(( "NULL rbuf" ));
     115           0 :     return NULL;
     116           0 :   }
     117             : 
     118           0 :   if( FD_UNLIKELY( rbuf_sz<FD_RESTORE_RBUF_MIN ) ) {
     119           0 :     FD_LOG_WARNING(( "rbuf_sz too small" ));
     120           0 :     return NULL;
     121           0 :   }
     122             : 
     123             :   /* Get the position and size of the checkpt.  If we can't (e.g. we are
     124             :      restoring from a non-seekable stream / pipe), treat the start of
     125             :      the checkpt as the fd's current position and the size as
     126             :      (practically) infinite. */
     127             : 
     128           0 :   ulong sz;
     129           0 :   ulong off;
     130             : 
     131           0 :   int err = fd_io_sz( fd, &sz );
     132           0 :   if( FD_LIKELY( !err ) ) err = fd_io_seek( fd, 0L, FD_IO_SEEK_TYPE_CUR, &off );
     133           0 :   if( FD_UNLIKELY( err ) ) { /* fd does not appear seekable */
     134           0 :     off = 0L;
     135           0 :     sz  = ULONG_MAX;
     136           0 :   } else if( FD_UNLIKELY( !((off<=sz) & (sz<=(ulong)LONG_MAX)) ) ) { /* fd claimed to be seekable but parameters are weird */
     137           0 :     FD_LOG_WARNING(( "sz too large or unexpected file position" ));
     138           0 :     return NULL;
     139           0 :   }
     140             : 
     141             :   /* Create decompressor */
     142             : 
     143           0 : # if FD_HAS_LZ4
     144           0 :   LZ4_streamDecode_t * lz4 = LZ4_createStreamDecode();
     145           0 :   if( FD_UNLIKELY( !lz4 ) ) {
     146           0 :     FD_LOG_WARNING(( "lz4 error" ));
     147           0 :     return NULL;
     148           0 :   }
     149             : # else
     150             :   void * lz4 = NULL;
     151             : # endif
     152             : 
     153             :   /* Init restore */
     154             : 
     155           0 :   fd_restore_t * restore = (fd_restore_t *)mem;
     156             : 
     157           0 :   restore->fd          = fd; /* streaming mode */
     158           0 :   restore->frame_style = 0;  /* not in frame */
     159           0 :   restore->lz4         = (void *)lz4;
     160           0 :   restore->sbuf_cursor = 0UL;
     161           0 :   restore->sz          = sz;
     162           0 :   restore->off         = off;
     163           0 :   restore->rbuf.mem    = (uchar *)rbuf;
     164           0 :   restore->rbuf.sz     = rbuf_sz;
     165           0 :   restore->rbuf.lo     = 0UL;
     166           0 :   restore->rbuf.ready  = 0UL;
     167             : 
     168           0 :   return restore;
     169           0 : }
     170             : 
     171             : fd_restore_t *
     172             : fd_restore_init_mmio( void *       mem,
     173             :                       void const * mmio,
     174           0 :                       ulong        mmio_sz ) {
     175             : 
     176             :   /* Check input args */
     177             : 
     178           0 :   if( FD_UNLIKELY( !mem ) ) {
     179           0 :     FD_LOG_WARNING(( "NULL mem" ));
     180           0 :     return NULL;
     181           0 :   }
     182             : 
     183           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_RESTORE_ALIGN ) ) ) {
     184           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     185           0 :     return NULL;
     186           0 :   }
     187             : 
     188           0 :   if( FD_UNLIKELY( (!mmio) & (!!mmio_sz) ) ) {
     189           0 :     FD_LOG_WARNING(( "NULL mmio with non-zero mmio_sz" ));
     190           0 :     return NULL;
     191           0 :   }
     192             : 
     193           0 :   if( FD_UNLIKELY( mmio_sz>(ulong)LONG_MAX ) ) {
     194           0 :     FD_LOG_WARNING(( "bad mmio_sz" ));
     195           0 :     return NULL;
     196           0 :   }
     197             : 
     198             :   /* Create decompressor */
     199             : 
     200           0 : # if FD_HAS_LZ4
     201           0 :   LZ4_streamDecode_t * lz4 = LZ4_createStreamDecode();
     202           0 :   if( FD_UNLIKELY( !lz4 ) ) {
     203           0 :     FD_LOG_WARNING(( "lz4 error" ));
     204           0 :     return NULL;
     205           0 :   }
     206             : # else
     207             :   void * lz4 = NULL;
     208             : # endif
     209             : 
     210             :   /* Init restore */
     211             : 
     212           0 :   fd_restore_t * restore = (fd_restore_t *)mem;
     213             : 
     214           0 :   restore->fd          = -1; /* mmio mode */
     215           0 :   restore->frame_style = 0;  /* not in frame */
     216           0 :   restore->lz4         = (void *)lz4;
     217           0 :   restore->sbuf_cursor = 0UL;
     218           0 :   restore->sz          = mmio_sz;
     219           0 :   restore->off         = 0UL;
     220           0 :   restore->mmio.mem    = (uchar const *)mmio;
     221             : 
     222           0 :   return restore;
     223           0 : }
     224             : 
     225             : void *
     226           0 : fd_restore_fini( fd_restore_t * restore ) {
     227             : 
     228           0 :   if( FD_UNLIKELY( !restore ) ) {
     229           0 :     FD_LOG_WARNING(( "NULL restore" ));
     230           0 :     return NULL;
     231           0 :   }
     232             : 
     233           0 :   if( FD_UNLIKELY( fd_restore_in_frame( restore ) ) ) {
     234           0 :     FD_LOG_WARNING(( "in a frame" ));
     235           0 :     restore->frame_style = -1; /* failed */
     236           0 :     return NULL;
     237           0 :   }
     238             : 
     239           0 : # if FD_HAS_LZ4
     240             : 
     241             :   /* Note: Though this this doesn't seem to be officially documented,
     242             :      the lz4-1.9.4@lz4/lib/lz4.c:2575 suggests that this always returns
     243             :      0.  That is, 0 is success and non-zero is failure. */
     244             : 
     245           0 :   if( FD_UNLIKELY( LZ4_freeStreamDecode( (LZ4_streamDecode_t *)restore->lz4 ) ) )
     246           0 :     FD_LOG_WARNING(( "LZ4 freeStreamDecode error, attempting to continue" ));
     247             : 
     248           0 : # endif
     249             : 
     250           0 :   return restore;
     251           0 : }
     252             : 
     253             : int
     254             : fd_restore_open_advanced( fd_restore_t * restore,
     255             :                           int            frame_style,
     256           0 :                           ulong *        _off ) {
     257             : 
     258           0 :   if( FD_UNLIKELY( !restore ) ) {
     259           0 :     FD_LOG_WARNING(( "NULL restore" ));
     260           0 :     return FD_CHECKPT_ERR_INVAL;
     261           0 :   }
     262             : 
     263           0 :   if( FD_UNLIKELY( !fd_restore_can_open( restore ) ) ) {
     264           0 :     FD_LOG_WARNING(( "in a frame or failed" ));
     265           0 :     restore->frame_style = -1; /* failed */
     266           0 :     return FD_CHECKPT_ERR_INVAL;
     267           0 :   }
     268             : 
     269           0 :   if( FD_UNLIKELY( !_off ) ) {
     270           0 :     FD_LOG_WARNING(( "NULL _off" ));
     271           0 :     restore->frame_style = -1; /* failed */
     272           0 :     return FD_CHECKPT_ERR_INVAL;
     273           0 :   }
     274             : 
     275           0 :   frame_style = fd_int_if( !!frame_style, frame_style, FD_CHECKPT_FRAME_STYLE_DEFAULT );
     276             : 
     277           0 :   switch( frame_style ) {
     278             : 
     279           0 :   case FD_CHECKPT_FRAME_STYLE_RAW: {
     280           0 :     break;
     281           0 :   }
     282             : 
     283           0 : # if FD_HAS_LZ4
     284           0 :   case FD_CHECKPT_FRAME_STYLE_LZ4: {
     285           0 :     if( FD_UNLIKELY( !LZ4_setStreamDecode( (LZ4_streamDecode_t *)restore->lz4, NULL, 0 ) ) ) {
     286           0 :       FD_LOG_WARNING(( "LZ4_setStreamDecode failed" ));
     287           0 :       restore->frame_style = -1; /* failed */
     288           0 :       return FD_CHECKPT_ERR_COMP;
     289           0 :     }
     290           0 :     restore->sbuf_cursor = 0UL;
     291           0 :     break;
     292           0 :   }
     293           0 : # endif
     294             : 
     295           0 :   default: {
     296           0 :     FD_LOG_WARNING(( "unsupported frame_style" ));
     297           0 :     restore->frame_style = -1; /* failed */
     298           0 :     return FD_CHECKPT_ERR_UNSUP;
     299           0 :   }
     300             : 
     301           0 :   }
     302             : 
     303           0 :   restore->frame_style = frame_style;
     304             : 
     305           0 :   *_off = restore->off;
     306           0 :   return FD_CHECKPT_SUCCESS;
     307           0 : }
     308             : 
     309             : int
     310             : fd_restore_close_advanced( fd_restore_t * restore,
     311           0 :                            ulong *        _off ) {
     312             : 
     313           0 :   if( FD_UNLIKELY( !restore ) ) {
     314           0 :     FD_LOG_WARNING(( "NULL restore" ));
     315           0 :     return FD_CHECKPT_ERR_INVAL;
     316           0 :   }
     317             : 
     318           0 :   if( FD_UNLIKELY( !fd_restore_in_frame( restore ) ) ) {
     319           0 :     FD_LOG_WARNING(( "not in a frame" ));
     320           0 :     restore->frame_style = -1; /* failed */
     321           0 :     return FD_CHECKPT_ERR_INVAL;
     322           0 :   }
     323             : 
     324           0 :   if( FD_UNLIKELY( !_off ) ) {
     325           0 :     FD_LOG_WARNING(( "NULL _off" ));
     326           0 :     restore->frame_style = -1; /* failed */
     327           0 :     return FD_CHECKPT_ERR_INVAL;
     328           0 :   }
     329             : 
     330           0 :   restore->frame_style = 0;
     331             : 
     332           0 :   *_off = restore->off;
     333           0 :   return FD_CHECKPT_SUCCESS;
     334           0 : }
     335             : 
     336             : int
     337             : fd_restore_seek( fd_restore_t * restore,
     338           0 :                  ulong          off ) {
     339             : 
     340           0 :   if( FD_UNLIKELY( !restore ) ) {
     341           0 :     FD_LOG_WARNING(( "NULL restore" ));
     342           0 :     return FD_CHECKPT_ERR_INVAL;
     343           0 :   }
     344             : 
     345           0 :   if( FD_UNLIKELY( !fd_restore_can_open( restore ) ) ) {
     346           0 :     FD_LOG_WARNING(( "restore in frame or failed" ));
     347           0 :     restore->frame_style = -1;/* failed */
     348           0 :     return FD_CHECKPT_ERR_INVAL;
     349           0 :   }
     350             : 
     351           0 :   ulong sz = restore->sz;
     352           0 :   if( FD_UNLIKELY( sz>(ulong)LONG_MAX ) ) {
     353           0 :     FD_LOG_WARNING(( "restore not seekable" ));
     354           0 :     restore->frame_style = -1;/* failed */
     355           0 :     return FD_CHECKPT_ERR_INVAL;
     356           0 :   }
     357             : 
     358           0 :   if( FD_UNLIKELY( off>sz ) ) {
     359           0 :     FD_LOG_WARNING(( "bad off" ));
     360           0 :     restore->frame_style = -1;/* failed */
     361           0 :     return FD_CHECKPT_ERR_INVAL;
     362           0 :   }
     363             : 
     364             :   /* Note: off<=sz<=LONG_MAX here */
     365             : 
     366           0 :   if( fd_restore_is_mmio( restore ) ) { /* mmio mode, app dependent branch prob */
     367             : 
     368           0 :     restore->off = off;
     369             : 
     370           0 :   } else {
     371             : 
     372             :     /* Compute the fd offset range [off0,off1) currently buffered at
     373             :        rbuf [0,lo+ready).  If off is in this range, update lo and ready
     374             :        accordingly.  Otherwise, seek the underlying fd to off and flush
     375             :        rbuf.  Note: though this theoretically could be used to support
     376             :        limited seeking within streams / pipes, we don't expose this as
     377             :        the API semantics would be tricky to make well defined, robust,
     378             :        predictable and easy to use. */
     379             : 
     380             :     /* Note: minimizing I/O seeks currently disabled because it is not a
     381             :        very important opt and it has no test coverage currently.  Set
     382             :        this to 1 to enable. */
     383             : #   if 0
     384             :     ulong off_old = restore->off;
     385             :     ulong off0    = off_old - restore->rbuf.lo;
     386             :     ulong off1    = off_old + restore->rbuf.ready;
     387             :     if( FD_UNLIKELY( (off0<=off) & (off<off1) ) ) {
     388             : 
     389             :       restore->off        = off;
     390             :       restore->rbuf.lo    = off  - off0;
     391             :       restore->rbuf.ready = off1 - off;
     392             : 
     393             :     } else
     394             : #   endif
     395             : 
     396           0 :     {
     397             : 
     398           0 :       ulong idx;
     399           0 :       int   err = fd_io_seek( restore->fd, (long)off, FD_IO_SEEK_TYPE_SET, &idx );
     400           0 :       if( FD_UNLIKELY( err ) ) {
     401           0 :         FD_LOG_WARNING(( "fd_io_seek failed (%i-%s)", err, fd_io_strerror( err ) ));
     402           0 :         restore->frame_style = -1; /* failed */
     403           0 :         return FD_CHECKPT_ERR_IO;
     404           0 :       }
     405             : 
     406           0 :       if( FD_UNLIKELY( idx!=off ) ) {
     407           0 :         FD_LOG_WARNING(( "unexpected fd_io_seek result" ));
     408           0 :         restore->frame_style = -1; /* failed */
     409           0 :         return FD_CHECKPT_ERR_IO;
     410           0 :       }
     411             : 
     412           0 :       restore->off        = off;
     413           0 :       restore->rbuf.lo    = 0UL;
     414           0 :       restore->rbuf.ready = 0UL;
     415             : 
     416           0 :     }
     417             : 
     418           0 :   }
     419             : 
     420           0 :   return FD_CHECKPT_SUCCESS;
     421           0 : }
     422             : 
     423             : static int
     424             : fd_restore_private_buf( fd_restore_t * restore,
     425             :                         void *         buf,
     426             :                         ulong          sz,
     427           0 :                         ulong          max ) {
     428             : 
     429           0 :   if( FD_UNLIKELY( !restore ) ) {
     430           0 :     FD_LOG_WARNING(( "NULL restore" ));
     431           0 :     return FD_CHECKPT_ERR_INVAL;
     432           0 :   }
     433             : 
     434           0 :   if( FD_UNLIKELY( !fd_restore_in_frame( restore ) ) ) {
     435           0 :     FD_LOG_WARNING(( "not in a frame" ));
     436           0 :     restore->frame_style = -1; /* failed */
     437           0 :     return FD_CHECKPT_ERR_INVAL;
     438           0 :   }
     439             : 
     440           0 :   if( FD_UNLIKELY( !sz ) ) return FD_CHECKPT_SUCCESS; /* nothing to do */
     441             : 
     442           0 :   if( FD_UNLIKELY( sz>max ) ) {
     443           0 :     FD_LOG_WARNING(( "sz too large" ));
     444           0 :     restore->frame_style = -1; /* failed */
     445           0 :     return FD_CHECKPT_ERR_INVAL;
     446           0 :   }
     447             : 
     448           0 :   if( FD_UNLIKELY( !buf ) ) {
     449           0 :     FD_LOG_WARNING(( "NULL buf with non-zero sz" ));
     450           0 :     restore->frame_style = -1; /* failed */
     451           0 :     return FD_CHECKPT_ERR_INVAL;
     452           0 :   }
     453             : 
     454           0 :   ulong off = restore->off;
     455             : 
     456           0 :   switch( restore->frame_style ) {
     457             : 
     458           0 :   case FD_CHECKPT_FRAME_STYLE_RAW: {
     459             : 
     460           0 :     if( fd_restore_is_mmio( restore ) ) { /* mmio mode, app dependent branch prob */
     461             : 
     462           0 :       ulong mmio_sz = restore->sz;
     463             : 
     464           0 :       if( FD_UNLIKELY( sz > (mmio_sz-off) ) ) {
     465           0 :         FD_LOG_WARNING(( "sz overflow" ));
     466           0 :         restore->frame_style = -1; /* failed */
     467           0 :         return FD_CHECKPT_ERR_IO;
     468           0 :       }
     469             : 
     470           0 :       memcpy( buf, restore->mmio.mem + off, sz );
     471             : 
     472           0 :     } else { /* streaming mode */
     473             : 
     474           0 :       int err = fd_io_buffered_read( restore->fd, buf, sz, restore->rbuf.mem, restore->rbuf.sz,
     475           0 :                                      &restore->rbuf.lo, &restore->rbuf.ready );
     476             : 
     477           0 :       if( FD_UNLIKELY( err ) ) {
     478           0 :         FD_LOG_WARNING(( "fd_io_buffered_read failed (%i-%s)", err, fd_io_strerror( err ) ));
     479           0 :         restore->frame_style = -1; /* failed */
     480           0 :         return FD_CHECKPT_ERR_IO;
     481           0 :       }
     482             : 
     483           0 :     }
     484             : 
     485           0 :     off += sz; /* at most mmio_sz */
     486           0 :     break;
     487           0 :   }
     488             : 
     489           0 : # if FD_HAS_LZ4
     490           0 :   case FD_CHECKPT_FRAME_STYLE_LZ4: {
     491             : 
     492           0 :     LZ4_streamDecode_t * lz4 = (LZ4_streamDecode_t *)restore->lz4;
     493             : 
     494           0 :     if( fd_restore_is_mmio( restore ) ) { /* mmio mode */
     495             : 
     496           0 :       uchar const * mmio    = restore->mmio.mem;
     497           0 :       ulong         mmio_sz = restore->sz;
     498             : 
     499           0 :       uchar * chunk = (uchar *)buf;
     500           0 :       do {
     501           0 :         ulong chunk_usz = fd_ulong_min( sz, FD_CHECKPT_PRIVATE_CHUNK_USZ_MAX );
     502             : 
     503           0 :         ulong chunk_csz = fd_restore_private_lz4( lz4, chunk, chunk_usz, mmio + off, mmio_sz - off,
     504           0 :                                                   restore->sbuf, FD_RESTORE_PRIVATE_SBUF_SZ, FD_RESTORE_META_MAX,
     505           0 :                                                   &restore->sbuf_cursor ); /* logs details */
     506           0 :         if( FD_UNLIKELY( !chunk_csz ) ) {
     507           0 :           restore->frame_style = -1; /* failed */
     508           0 :           return FD_CHECKPT_ERR_COMP;
     509           0 :         }
     510             : 
     511           0 :         off += chunk_csz; /* at most mmio_sz */
     512             : 
     513           0 :         chunk += chunk_usz;
     514           0 :         sz    -= chunk_usz;
     515           0 :       } while( sz );
     516             : 
     517           0 :     } else { /* streaming mode */
     518             : 
     519           0 :       int     fd         = restore->fd;
     520           0 :       uchar * rbuf       = restore->rbuf.mem;
     521           0 :       ulong   rbuf_sz    = restore->rbuf.sz;
     522           0 :       ulong   rbuf_lo    = restore->rbuf.lo;
     523           0 :       ulong   rbuf_ready = restore->rbuf.ready;
     524             : 
     525           0 :       uchar * chunk = (uchar *)buf;
     526           0 :       do {
     527           0 :         ulong chunk_usz = fd_ulong_min( sz, FD_CHECKPT_PRIVATE_CHUNK_USZ_MAX );
     528             : 
     529             :         /* Pre-buffer the header and the first body byte to figure out
     530             :            how large the compressed chunk actually is.
     531             : 
     532             :            Note: This can buffer bytes past the end of the checkpoint in
     533             :            the uncommon case of there being data past the end of the
     534             :            checkpoint (e.g. is a stream like stdin without an EOF or the
     535             :            checkpoint is embedded in a larger file).  We could have
     536             :            fd_io_read below use min_sz-rbuf_ready for the min and max sz
     537             :            arguments to not overread (but then there isn't much point to
     538             :            using buffered reads).  We could also make an unbuffered
     539             :            streaming a restore option (but it probably much slower if
     540             :            there are lots of tiny buffers).  Regardless, overreading in
     541             :            such scenarios is an unavoidable possibility if the incoming
     542             :            file is corrupt anyway and the caller will usually be able to
     543             :            seek such streams.  So we currently just allow it to get the
     544             :            benefits of buffering. */
     545             : 
     546           0 : #       define BUFFER(min_ready)                                                                         \
     547           0 :         if( FD_UNLIKELY( rbuf_ready<min_ready ) ) { /* If not enough bytes buffered */                   \
     548             :                                                                                                          \
     549             :           /* Move the unprocessed bytes to the beginning of the buffer */                                \
     550           0 :                                                                                                          \
     551           0 :           if( FD_LIKELY( (rbuf_lo>0UL) & (rbuf_ready>0UL) ) ) memmove( rbuf, rbuf+rbuf_lo, rbuf_ready ); \
     552           0 :                                                                                                          \
     553             :           /* Read at least enough bytes to make progress and at most */                                  \
     554             :           /* enough bytes to fill the rbuf.  If we hit EOF or another */                                 \
     555             :           /* error, the restore failed. */                                                               \
     556           0 :                                                                                                          \
     557           0 :           ulong rsz;                                                                                     \
     558           0 :           int   err = fd_io_read( fd, rbuf+rbuf_ready, min_ready-rbuf_ready, rbuf_sz-rbuf_ready, &rsz ); \
     559           0 :           if( FD_UNLIKELY( err ) ) {                                                                     \
     560           0 :             FD_LOG_WARNING(( "fd_io_read failed (%i-%s)", err, fd_io_strerror( err ) ));                 \
     561           0 :             restore->frame_style = -1; /* failed */                                                      \
     562           0 :             return FD_CHECKPT_ERR_IO;                                                                    \
     563           0 :           }                                                                                              \
     564           0 :                                                                                                          \
     565           0 :           rbuf_ready += rsz; /* in [min_ready,rbuf_sz] */                                                \
     566           0 :           rbuf_lo     = 0UL;                                                                             \
     567           0 :         }
     568             : 
     569           0 :         BUFFER( 4UL )
     570             : 
     571           0 :         ulong chunk_csz = 3UL + ( ((ulong)rbuf[ rbuf_lo     ]      )
     572           0 :                                 | ((ulong)rbuf[ rbuf_lo+1UL ] <<  8)
     573           0 :                                 | ((ulong)rbuf[ rbuf_lo+2UL ] << 16) );
     574             : 
     575           0 :         if( FD_UNLIKELY( !((4UL<=chunk_csz) & (chunk_csz<=FD_CHECKPT_PRIVATE_CSZ_MAX( chunk_usz ))) ) ) {
     576           0 :           FD_LOG_WARNING(( "corrupt header" ));
     577           0 :           restore->frame_style = -1; /* failed */
     578           0 :           return FD_CHECKPT_ERR_COMP;
     579           0 :         }
     580             : 
     581             :         /* Buffer the compressed chunk.  If the fd doesn't have
     582             :            chunk_csz bytes available (e.g. we hit EOF unexpectedly or
     583             :            other I/O error), this will fail the restore.  Note that we
     584             :            haven't advanced rbuf_lo yet so we invoke buffer with the
     585             :            entire chunk_csz.  Also note that at this point:
     586             : 
     587             :              rbuf_sz >= RBUF_MIN >= CSZ_MAX( USZ_MAX ) >= CSZ_MAX( chunk_usz ) >= chunk_csz
     588             : 
     589             :            such that we always can buffer chunk_csz bytes into rbuf. */
     590             : 
     591           0 :         BUFFER( chunk_csz );
     592             : 
     593             :         /* Decompress the compressed chunk in rbuf */
     594             : 
     595           0 :         ulong res = fd_restore_private_lz4( lz4, chunk, chunk_usz, rbuf + rbuf_lo, rbuf_ready,
     596           0 :                                             restore->sbuf, FD_RESTORE_PRIVATE_SBUF_SZ, FD_RESTORE_META_MAX,
     597           0 :                                             &restore->sbuf_cursor ); /* logs details */
     598           0 :         if( FD_UNLIKELY( !res ) ) {
     599           0 :           restore->frame_style = -1; /* failed */
     600           0 :           return FD_CHECKPT_ERR_COMP;
     601           0 :         }
     602             : 
     603           0 :         if( FD_UNLIKELY( res!=chunk_csz ) ) {
     604           0 :           FD_LOG_WARNING(( "corrupt body" ));
     605           0 :           restore->frame_style = -1; /* failed */
     606           0 :           return FD_CHECKPT_ERR_COMP;
     607           0 :         }
     608             : 
     609           0 : #       undef BUFFER
     610             : 
     611           0 :         rbuf_lo    += chunk_csz;
     612           0 :         rbuf_ready -= chunk_csz;
     613             : 
     614           0 :         off += chunk_csz;
     615             : 
     616           0 :         chunk += chunk_usz;
     617           0 :         sz    -= chunk_usz;
     618           0 :       } while( sz );
     619             : 
     620           0 :       restore->rbuf.lo    = rbuf_lo;
     621           0 :       restore->rbuf.ready = rbuf_ready;
     622             : 
     623           0 :     }
     624             : 
     625           0 :     break;
     626           0 :   }
     627           0 : # endif
     628             : 
     629           0 :   default: { /* never get here */
     630           0 :     FD_LOG_WARNING(( "unsupported frame style" ));
     631           0 :     restore->frame_style = -1; /* failed */
     632           0 :     return FD_CHECKPT_ERR_UNSUP;
     633           0 :   }
     634             : 
     635           0 :   }
     636             : 
     637           0 :   restore->off = off;
     638           0 :   return FD_CHECKPT_SUCCESS;
     639           0 : }
     640             : 
     641             : int
     642             : fd_restore_meta( fd_restore_t * restore,
     643             :                  void *         buf,
     644           0 :                  ulong          sz ) {
     645           0 :   return fd_restore_private_buf( restore, buf, sz, FD_CHECKPT_META_MAX );
     646           0 : }
     647             : 
     648             : int
     649             : fd_restore_data( fd_restore_t * restore,
     650             :                  void *         buf,
     651           0 :                  ulong          sz ) {
     652           0 :   return fd_restore_private_buf( restore, buf, sz, ULONG_MAX );
     653           0 : }

Generated by: LCOV version 1.14