[BACK]Return to blocks.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rsync

Diff for /src/usr.bin/rsync/blocks.c between version 1.8 and 1.9

version 1.8, 2019/02/16 16:57:48 version 1.9, 2019/02/16 16:58:39
Line 30 
Line 30 
 #include "extern.h"  #include "extern.h"
   
 /*  /*
  * Flush out "size" bytes of the buffer, doing all of the appropriate  
  * chunking of the data, then the subsequent token (or zero).  
  * Return zero on failure, non-zero on success.  
  */  
 static int  
 blk_flush(struct sess *sess, int fd,  
         const void *b, off_t size, int32_t token)  
 {  
         off_t   i = 0, sz;  
   
         while (i < size) {  
                 sz = MAX_CHUNK < (size - i) ?  
                         MAX_CHUNK : (size - i);  
                 if (!io_write_int(sess, fd, sz)) {  
                         ERRX1(sess, "io_write_int");  
                         return 0;  
                 } else if (!io_write_buf(sess, fd, b + i, sz)) {  
                         ERRX1(sess, "io_write_buf");  
                         return 0;  
                 }  
                 i += sz;  
         }  
   
         if (!io_write_int(sess, fd, token)) {  
                 ERRX1(sess, "io_write_int");  
                 return 0;  
         }  
   
         return 1;  
 }  
   
 /*  
  * From our current position of "offs" in buffer "buf" of total size   * From our current position of "offs" in buffer "buf" of total size
  * "size", see if we can find a matching block in our list of blocks.   * "size", see if we can find a matching block in our list of blocks.
  * The "hint" refers to the block that *might* work.   * The "hint" refers to the block that *might* work.
Line 146 
Line 114 
 }  }
   
 /*  /*
  * The main reconstruction algorithm on the sender side.   * Given a local file "path" and the blocks created by a remote machine,
  * This is reentrant: it's meant to be called whenever "fd" unblocks for   * find out which blocks of our file they don't have and send them.
  * writing by the sender.   * This function is reentrant: it must be called while there's still
  * Scans byte-wise over the input file, looking for matching blocks in   * data to send.
  * what the server sent us.  
  * If a block is found, emit all data up until the block, then the token  
  * for the block.  
  * The receiving end can then reconstruct the file trivially.  
  * Return zero on failure, non-zero on success.  
  */   */
 static int  void
 blk_match_send(struct sess *sess, const char *path, int fd,  blk_match(struct sess *sess, const struct blkset *blks,
         const struct blkset *blks, struct blkstat *st)          const char *path, struct blkstat *st)
 {  {
         off_t            last, end, sz;          off_t            last, end, sz;
         int32_t          tok;          int32_t          tok;
         struct blk      *blk;          struct blk      *blk;
   
         /*          /*
          * Stop searching at the length of the file minus the size of           * If the file's empty or we don't have any blocks from the
          * the last block.           * sender, then simply send the whole file.
          * The reason for this being that we don't need to do an           * Otherwise, run the hash matching routine and send raw chunks
          * incremental hash within the last block---if it doesn't match,           * and subsequent matching tokens.
          * it doesn't match.  
          */           */
   
         end = st->mapsz + 1 - blks->blks[blks->blksz - 1].len;          if (st->mapsz && blks->blksz) {
         last = st->offs;  
   
         for ( ; st->offs < end; st->offs++) {  
                 blk = blk_find(sess, st->map, st->mapsz,  
                         st->offs, blks, path, st->hint);  
                 if (blk == NULL)  
                         continue;  
   
                 sz = st->offs - last;  
                 st->dirty += sz;  
                 st->total += sz;  
                 LOG4(sess, "%s: flushing %jd B before %zu B "  
                         "block %zu", path, (intmax_t)sz, blk->len, blk->idx);  
                 tok = -(blk->idx + 1);  
   
                 /*                  /*
                  * Write the data we have, then follow it with the tag                   * Stop searching at the length of the file minus the
                  * of the block that matches.                   * size of the last block.
                  * The receiver will then write our data, then the data                   * The reason for this being that we don't need to do an
                  * it already has in the matching block.                   * incremental hash within the last block---if it
                    * doesn't match, it doesn't match.
                  */                   */
   
                 if (!blk_flush(sess, fd, st->map + last, sz, tok)) {                  end = st->mapsz + 1 - blks->blks[blks->blksz - 1].len;
                         ERRX1(sess, "blk_flush");                  last = st->offs;
                         return -1;  
                 }  
   
                 st->total += blk->len;                  for ( ; st->offs < end; st->offs++) {
                 st->offs += blk->len;                          blk = blk_find(sess, st->map, st->mapsz,
                 st->hint = blk->idx + 1;                                  st->offs, blks, path, st->hint);
                 return 0;                          if (blk == NULL)
         }                                  continue;
   
         /* Emit remaining data and send terminator token. */                          sz = st->offs - last;
                           st->dirty += sz;
                           st->total += sz;
                           LOG4(sess, "%s: flushing %jd B before %zu B "
                                   "block %zu", path, (intmax_t)sz,
                                   blk->len, blk->idx);
                           tok = -(blk->idx + 1);
   
         sz = st->mapsz - last;                          /*
         st->total += sz;                           * Write the data we have, then follow it with
         st->dirty += sz;                           * the tag of the block that matches.
                            */
   
         LOG4(sess, "%s: flushing remaining %jd B", path, (intmax_t)sz);                          st->curpos = last;
                           st->curlen = st->curpos + sz;
                           st->curtok = tok;
                           assert(0 != st->curtok);
                           st->curst = sz ? BLKSTAT_DATA : BLKSTAT_TOK;
                           st->total += blk->len;
                           st->offs += blk->len;
                           st->hint = blk->idx + 1;
                           return;
                   }
   
         if (!blk_flush(sess, fd, st->map + last, sz, 0)) {                  /* Emit remaining data and send terminator token. */
                 ERRX1(sess, "blk_flush");  
                 return -1;  
         }  
   
         LOG3(sess, "%s: flushed (chunked) %jd B total, "                  sz = st->mapsz - last;
                 "%.2f%% upload ratio", path, (intmax_t)st->total,                  LOG4(sess, "%s: flushing remaining %jd B",
                 100.0 * st->dirty / st->total);                          path, (intmax_t)sz);
         return 1;  
 }  
   
 /*                  st->total += sz;
  * Given a local file "path" and the blocks created by a remote machine,                  st->dirty += sz;
  * find out which blocks of our file they don't have and send them.                  st->curpos = last;
  * This function is reentrant: it must be called while there's still                  st->curlen = st->curpos + sz;
  * data to send.                  st->curtok = 0;
  * Return 0 if there's more data to send, >0 if the file has completed                  st->curst = sz ? BLKSTAT_DATA : BLKSTAT_TOK;
  * its update, or <0 on error.  
  */  
 int  
 blk_match(struct sess *sess, int fd, const struct blkset *blks,  
         const char *path, struct blkstat *st)  
 {  
         unsigned char    filemd[MD4_DIGEST_LENGTH];  
         int              c;  
   
         /*  
          * If the file's empty or we don't have any blocks from the  
          * sender, then simply send the whole file.  
          * Otherwise, run the hash matching routine and send raw chunks  
          * and subsequent matching tokens.  
          */  
   
         if (st->mapsz && blks->blksz) {  
                 if ((c = blk_match_send(sess, path, fd, blks, st)) < 0) {  
                         ERRX1(sess, "blk_match_send");  
                         return -1;  
                 } else if (c == 0)  
                         return 0;  
         } else {          } else {
                 if (!blk_flush(sess, fd, st->map, st->mapsz, 0)) {                  st->curpos = 0;
                         ERRX1(sess, "blk_flush");                  st->curlen = st->mapsz;
                         return -1;                  st->curtok = 0;
                 }                  st->curst = st->mapsz ? BLKSTAT_DATA : BLKSTAT_TOK;
                 LOG3(sess, "%s: flushed (un-chunked) %jd B, 100%% upload ratio",                  st->dirty = st->total = st->mapsz;
                     path, (intmax_t)st->mapsz);  
         }  
   
         /*                  LOG4(sess, "%s: flushing whole file %zu B",
          * Now write the full file hash.                          path, st->mapsz);
          * Since we're seeding the hash, this always gives us some sort  
          * of data even if the file's zero-length.  
          */  
   
         hash_file(st->map, st->mapsz, filemd, sess);  
   
         if (!io_write_buf(sess, fd, filemd, MD4_DIGEST_LENGTH)) {  
                 ERRX1(sess, "io_write_buf");  
                 return -1;  
         }          }
   
         return 1;  
 }  }
   
 /*  /*

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.9