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

Diff for /src/usr.bin/rsync/uploader.c between version 1.24 and 1.24.2.1

version 1.24, 2021/03/22 11:20:04 version 1.24.2.1, 2021/11/09 13:41:24
Line 19 
Line 19 
 #include <sys/stat.h>  #include <sys/stat.h>
   
 #include <assert.h>  #include <assert.h>
   #include <err.h>
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  #include <fcntl.h>
 #include <inttypes.h>  #include <inttypes.h>
Line 33 
Line 34 
   
 enum    uploadst {  enum    uploadst {
         UPLOAD_FIND_NEXT = 0, /* find next to upload to sender */          UPLOAD_FIND_NEXT = 0, /* find next to upload to sender */
         UPLOAD_WRITE_LOCAL, /* wait to write to sender */          UPLOAD_WRITE, /* wait to write to sender */
         UPLOAD_READ_LOCAL, /* wait to read from local file */  
         UPLOAD_FINISHED /* nothing more to do in phase */          UPLOAD_FINISHED /* nothing more to do in phase */
 };  };
   
Line 80 
Line 80 
  * operator that we're a link.   * operator that we're a link.
  */   */
 static void  static void
 log_link(struct sess *sess, const struct flist *f)  log_symlink(struct sess *sess, const struct flist *f)
 {  {
   
         if (!sess->opts->server)          if (!sess->opts->server)
Line 167 
Line 167 
  * Return <0 on failure 0 on success.   * Return <0 on failure 0 on success.
  */   */
 static int  static int
 pre_link(struct upload *p, struct sess *sess)  pre_symlink(struct upload *p, struct sess *sess)
 {  {
         struct stat              st;          struct stat              st;
         const struct flist      *f;          const struct flist      *f;
Line 180 
Line 180 
         if (!sess->opts->preserve_links) {          if (!sess->opts->preserve_links) {
                 WARNX("%s: ignoring symlink", f->path);                  WARNX("%s: ignoring symlink", f->path);
                 return 0;                  return 0;
         } else if (sess->opts->dry_run) {          }
                 log_link(sess, f);          if (sess->opts->dry_run) {
                   log_symlink(sess, f);
                 return 0;                  return 0;
         }          }
   
Line 194 
Line 195 
   
         assert(p->rootfd != -1);          assert(p->rootfd != -1);
         rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);          rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
   
           if (rc == -1 && errno != ENOENT) {
                   ERR("%s: fstatat", f->path);
                   return -1;
           }
         if (rc != -1 && !S_ISLNK(st.st_mode)) {          if (rc != -1 && !S_ISLNK(st.st_mode)) {
                 if (S_ISDIR(st.st_mode) &&                  if (S_ISDIR(st.st_mode) &&
                     unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {                      unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
Line 201 
Line 207 
                         return -1;                          return -1;
                 }                  }
                 rc = -1;                  rc = -1;
         } else if (rc == -1 && errno != ENOENT) {  
                 ERR("%s: fstatat", f->path);  
                 return -1;  
         }          }
   
         /*          /*
Line 259 
Line 262 
                 free(temp);                  free(temp);
         }          }
   
         log_link(sess, f);          log_symlink(sess, f);
         return 0;          return 0;
 }  }
   
 /*  /*
  * See pre_link(), but for devices.   * See pre_symlink(), but for devices.
  * FIXME: this is very similar to the other pre_xxx() functions.   * FIXME: this is very similar to the other pre_xxx() functions.
  * Return <0 on failure 0 on success.   * Return <0 on failure 0 on success.
  */   */
Line 282 
Line 285 
         if (!sess->opts->devices || getuid() != 0) {          if (!sess->opts->devices || getuid() != 0) {
                 WARNX("skipping non-regular file %s", f->path);                  WARNX("skipping non-regular file %s", f->path);
                 return 0;                  return 0;
         } else if (sess->opts->dry_run) {          }
           if (sess->opts->dry_run) {
                 log_file(sess, f);                  log_file(sess, f);
                 return 0;                  return 0;
         }          }
Line 296 
Line 300 
         assert(p->rootfd != -1);          assert(p->rootfd != -1);
         rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);          rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
   
           if (rc == -1 && errno != ENOENT) {
                   ERR("%s: fstatat", f->path);
                   return -1;
           }
         if (rc != -1 && !(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) {          if (rc != -1 && !(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) {
                 if (S_ISDIR(st.st_mode) &&                  if (S_ISDIR(st.st_mode) &&
                     unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {                      unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
Line 303 
Line 311 
                         return -1;                          return -1;
                 }                  }
                 rc = -1;                  rc = -1;
         } else if (rc == -1 && errno != ENOENT) {  
                 ERR("%s: fstatat", f->path);  
                 return -1;  
         }          }
   
         /* Make sure existing device is of the correct type. */          /* Make sure existing device is of the correct type. */
Line 351 
Line 356 
 }  }
   
 /*  /*
  * See pre_link(), but for FIFOs.   * See pre_symlink(), but for FIFOs.
  * FIXME: this is very similar to the other pre_xxx() functions.   * FIXME: this is very similar to the other pre_xxx() functions.
  * Return <0 on failure 0 on success.   * Return <0 on failure 0 on success.
  */   */
Line 369 
Line 374 
         if (!sess->opts->specials) {          if (!sess->opts->specials) {
                 WARNX("skipping non-regular file %s", f->path);                  WARNX("skipping non-regular file %s", f->path);
                 return 0;                  return 0;
         } else if (sess->opts->dry_run) {          }
           if (sess->opts->dry_run) {
                 log_file(sess, f);                  log_file(sess, f);
                 return 0;                  return 0;
         }          }
Line 383 
Line 389 
         assert(p->rootfd != -1);          assert(p->rootfd != -1);
         rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);          rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
   
           if (rc == -1 && errno != ENOENT) {
                   ERR("%s: fstatat", f->path);
                   return -1;
           }
         if (rc != -1 && !S_ISFIFO(st.st_mode)) {          if (rc != -1 && !S_ISFIFO(st.st_mode)) {
                 if (S_ISDIR(st.st_mode) &&                  if (S_ISDIR(st.st_mode) &&
                     unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {                      unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
Line 390 
Line 400 
                         return -1;                          return -1;
                 }                  }
                 rc = -1;                  rc = -1;
         } else if (rc == -1 && errno != ENOENT) {  
                 ERR("%s: fstatat", f->path);  
                 return -1;  
         }          }
   
         if (rc == -1) {          if (rc == -1) {
Line 426 
Line 433 
 }  }
   
 /*  /*
  * See pre_link(), but for socket files.   * See pre_symlink(), but for socket files.
  * FIXME: this is very similar to the other pre_xxx() functions.   * FIXME: this is very similar to the other pre_xxx() functions.
  * Return <0 on failure 0 on success.   * Return <0 on failure 0 on success.
  */   */
Line 444 
Line 451 
         if (!sess->opts->specials) {          if (!sess->opts->specials) {
                 WARNX("skipping non-regular file %s", f->path);                  WARNX("skipping non-regular file %s", f->path);
                 return 0;                  return 0;
         } else if (sess->opts->dry_run) {          }
           if (sess->opts->dry_run) {
                 log_file(sess, f);                  log_file(sess, f);
                 return 0;                  return 0;
         }          }
Line 458 
Line 466 
         assert(p->rootfd != -1);          assert(p->rootfd != -1);
         rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);          rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
   
           if (rc == -1 && errno != ENOENT) {
                   ERR("%s: fstatat", f->path);
                   return -1;
           }
         if (rc != -1 && !S_ISSOCK(st.st_mode)) {          if (rc != -1 && !S_ISSOCK(st.st_mode)) {
                 if (S_ISDIR(st.st_mode) &&                  if (S_ISDIR(st.st_mode) &&
                     unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {                      unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
Line 465 
Line 477 
                         return -1;                          return -1;
                 }                  }
                 rc = -1;                  rc = -1;
         } else if (rc == -1 && errno != ENOENT) {  
                 ERR("%s: fstatat", f->path);  
                 return -1;  
         }          }
   
         if (rc == -1) {          if (rc == -1) {
Line 518 
Line 527 
         if (!sess->opts->recursive) {          if (!sess->opts->recursive) {
                 WARNX("%s: ignoring directory", f->path);                  WARNX("%s: ignoring directory", f->path);
                 return 0;                  return 0;
         } else if (sess->opts->dry_run) {          }
           if (sess->opts->dry_run) {
                 log_dir(sess, f);                  log_dir(sess, f);
                 return 0;                  return 0;
         }          }
Line 529 
Line 539 
         if (rc == -1 && errno != ENOENT) {          if (rc == -1 && errno != ENOENT) {
                 ERR("%s: fstatat", f->path);                  ERR("%s: fstatat", f->path);
                 return -1;                  return -1;
         } else if (rc != -1 && !S_ISDIR(st.st_mode)) {          }
           if (rc != -1 && !S_ISDIR(st.st_mode)) {
                 ERRX("%s: not a directory", f->path);                  ERRX("%s: not a directory", f->path);
                 return -1;                  return -1;
         } else if (rc != -1) {          } else if (rc != -1) {
Line 579 
Line 590 
   
         if (!sess->opts->recursive)          if (!sess->opts->recursive)
                 return 1;                  return 1;
         else if (sess->opts->dry_run)          if (sess->opts->dry_run)
                 return 1;                  return 1;
   
         if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) {          if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
                 ERR("%s: fstatat", f->path);                  ERR("%s: fstatat", f->path);
                 return 0;                  return 0;
         } else if (!S_ISDIR(st.st_mode)) {          }
           if (!S_ISDIR(st.st_mode)) {
                 WARNX("%s: not a directory", f->path);                  WARNX("%s: not a directory", f->path);
                 return 0;                  return 0;
         }          }
Line 630 
Line 642 
 }  }
   
 /*  /*
    * Check if file exists in the specified root directory.
    * Returns:
    *    -1 on error
    *     0 if file is considered the same
    *     1 if file exists and is possible match
    *     2 if file exists but quick check failed
    *     3 if file does not exist
    * The stat pointer st is only valid for 0, 1, and 2 returns.
    */
   static int
   check_file(int rootfd, const struct flist *f, struct stat *st)
   {
           if (fstatat(rootfd, f->path, st, AT_SYMLINK_NOFOLLOW) == -1) {
                   if (errno == ENOENT)
                           return 3;
   
                   ERR("%s: fstatat", f->path);
                   return -1;
           }
   
           /* non-regular file needs attention */
           if (!S_ISREG(st->st_mode))
                   return 2;
   
           /* quick check if file is the same */
           /* TODO: add support for --checksum, --size-only and --ignore-times */
           if (st->st_size == f->st.size) {
                   if (st->st_mtime == f->st.mtime)
                           return 0;
                   return 1;
           }
   
           /* file needs attention */
           return 2;
   }
   
   /*
  * Try to open the file at the current index.   * Try to open the file at the current index.
  * If the file does not exist, returns with success.   * If the file does not exist, returns with >0.
  * Return <0 on failure, 0 on success w/nothing to be done, >0 on   * Return <0 on failure, 0 on success w/nothing to be done, >0 on
  * success and the file needs attention.   * success and the file needs attention.
  */   */
 static int  static int
 pre_file(const struct upload *p, int *filefd, struct sess *sess)  pre_file(const struct upload *p, int *filefd, off_t *size,
       struct sess *sess)
 {  {
         const struct flist *f;          const struct flist *f;
           struct stat st;
           int i, rc, match = -1;
   
         f = &p->fl[p->idx];          f = &p->fl[p->idx];
         assert(S_ISREG(f->st.mode));          assert(S_ISREG(f->st.mode));
Line 652 
Line 704 
                 return 0;                  return 0;
         }          }
   
           if (sess->opts->max_size >= 0 && f->st.size > sess->opts->max_size) {
                   WARNX("skipping over max-size file %s", f->path);
                   return 0;
           }
           if (sess->opts->min_size >= 0 && f->st.size < sess->opts->min_size) {
                   WARNX("skipping under min-size file %s", f->path);
                   return 0;
           }
   
         /*          /*
          * For non dry-run cases, we'll write the acknowledgement later           * For non dry-run cases, we'll write the acknowledgement later
          * in the rsync_uploader() function because we need to wait for           * in the rsync_uploader() function.
          * the open() call to complete.  
          * If the call to openat() fails with ENOENT, there's a  
          * fast-path between here and the write function, so we won't do  
          * any blocking between now and then.  
          */           */
   
         *filefd = openat(p->rootfd, f->path,          *size = 0;
                 O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0);          *filefd = -1;
         if (*filefd != -1 || errno == ENOENT)  
                 return 1;          rc = check_file(p->rootfd, f, &st);
         ERR("%s: openat", f->path);          if (rc == -1)
         return -1;                  return -1;
           if (rc == 2 && !S_ISREG(st.st_mode)) {
                   if (S_ISDIR(st.st_mode) &&
                       unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
                           ERR("%s: unlinkat", f->path);
                           return -1;
                   }
           }
           if (rc == 0) {
                   if (!rsync_set_metadata_at(sess, 0, p->rootfd, f, f->path)) {
                           ERRX1("rsync_set_metadata");
                           return -1;
                   }
                   LOG3("%s: skipping: up to date", f->path);
                   return 0;
           }
   
           /* check alternative locations for better match */
           for (i = 0; sess->opts->basedir[i] != NULL; i++) {
                   const char *root = sess->opts->basedir[i];
                   int dfd, x;
   
                   dfd = openat(p->rootfd, root, O_RDONLY | O_DIRECTORY);
                   if (dfd == -1)
                           err(ERR_FILE_IO, "%s: openat", root);
                   x = check_file(dfd, f, &st);
                   /* found a match */
                   if (x == 0) {
                           if (rc >= 0) {
                                   /* found better match, delete file in rootfd */
                                   if (unlinkat(p->rootfd, f->path, 0) == -1 &&
                                       errno != ENOENT) {
                                           ERR("%s: unlinkat", f->path);
                                           return -1;
                                   }
                           }
                           LOG3("%s: skipping: up to date in %s", f->path, root);
                           /* TODO: depending on mode link or copy file */
                           close(dfd);
                           return 0;
                   } else if (x == 1 && match == -1) {
                           /* found a local file that is a close match */
                           match = i;
                   }
                   close(dfd);
           }
           if (match != -1) {
                   /* copy match from basedir into root as a start point */
                   copy_file(p->rootfd, sess->opts->basedir[match], f);
                   if (fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) ==
                       -1) {
                           ERR("%s: fstatat", f->path);
                           return -1;
                   }
           }
   
           *size = st.st_size;
           *filefd = openat(p->rootfd, f->path, O_RDONLY | O_NOFOLLOW);
           if (*filefd == -1 && errno != ENOENT) {
                   ERR("%s: openat", f->path);
                   return -1;
           }
   
           /* file needs attention */
           return 1;
 }  }
   
 /*  /*
Line 737 
Line 858 
         struct sess *sess, int *fileoutfd)          struct sess *sess, int *fileoutfd)
 {  {
         struct blkset       blk;          struct blkset       blk;
         struct stat         st;  
         void               *mbuf, *bufp;          void               *mbuf, *bufp;
         ssize_t             msz;          ssize_t             msz;
         size_t              i, pos, sz;          size_t              i, pos, sz;
         off_t               offs;          off_t               offs, filesize;
         int                 c;          int                 c;
         const struct flist *f;  
   
         /* This should never get called. */          /* Once finished this should never get called again. */
   
         assert(u->state != UPLOAD_FINISHED);          assert(u->state != UPLOAD_FINISHED);
   
         /*          /*
Line 756 
Line 874 
          * have a valid buffer to write.           * have a valid buffer to write.
          */           */
   
         if (u->state == UPLOAD_WRITE_LOCAL) {          if (u->state == UPLOAD_WRITE) {
                 assert(u->buf != NULL);                  assert(u->buf != NULL);
                 assert(*fileoutfd != -1);                  assert(*fileoutfd != -1);
                 assert(*fileinfd == -1);                  assert(*fileinfd == -1);
Line 810 
Line 928 
                         if (S_ISDIR(u->fl[u->idx].st.mode))                          if (S_ISDIR(u->fl[u->idx].st.mode))
                                 c = pre_dir(u, sess);                                  c = pre_dir(u, sess);
                         else if (S_ISLNK(u->fl[u->idx].st.mode))                          else if (S_ISLNK(u->fl[u->idx].st.mode))
                                 c = pre_link(u, sess);                                  c = pre_symlink(u, sess);
                         else if (S_ISREG(u->fl[u->idx].st.mode))                          else if (S_ISREG(u->fl[u->idx].st.mode))
                                 c = pre_file(u, fileinfd, sess);                                  c = pre_file(u, fileinfd, &filesize, sess);
                         else if (S_ISBLK(u->fl[u->idx].st.mode) ||                          else if (S_ISBLK(u->fl[u->idx].st.mode) ||
                             S_ISCHR(u->fl[u->idx].st.mode))                              S_ISCHR(u->fl[u->idx].st.mode))
                                 c = pre_dev(u, sess);                                  c = pre_dev(u, sess);
Line 848 
Line 966 
   
                 /* Go back to the event loop, if necessary. */                  /* Go back to the event loop, if necessary. */
   
                 u->state = (*fileinfd == -1) ?                  u->state = UPLOAD_WRITE;
                         UPLOAD_WRITE_LOCAL : UPLOAD_READ_LOCAL;  
                 if (u->state == UPLOAD_READ_LOCAL)  
                         return 1;  
         }          }
   
         /*  
          * If an input file is open, stat it and see if it's already up  
          * to date, in which case close it and go to the next one.  
          * Either way, we don't have a write channel open.  
          */  
   
         if (u->state == UPLOAD_READ_LOCAL) {  
                 assert(*fileinfd != -1);  
                 assert(*fileoutfd == -1);  
                 f = &u->fl[u->idx];  
   
                 if (fstat(*fileinfd, &st) == -1) {  
                         ERR("%s: fstat", f->path);  
                         close(*fileinfd);  
                         *fileinfd = -1;  
                         return -1;  
                 } else if (!S_ISREG(st.st_mode)) {  
                         ERRX("%s: not regular", f->path);  
                         close(*fileinfd);  
                         *fileinfd = -1;  
                         return -1;  
                 }  
   
                 if (st.st_size == f->st.size &&  
                     st.st_mtime == f->st.mtime) {  
                         LOG3("%s: skipping: up to date", f->path);  
                         if (!rsync_set_metadata  
                             (sess, 0, *fileinfd, f, f->path)) {  
                                 ERRX1("rsync_set_metadata");  
                                 close(*fileinfd);  
                                 *fileinfd = -1;  
                                 return -1;  
                         }  
                         close(*fileinfd);  
                         *fileinfd = -1;  
                         *fileoutfd = u->fdout;  
                         u->state = UPLOAD_FIND_NEXT;  
                         u->idx++;  
                         return 1;  
                 }  
   
                 /* Fallthrough... */  
   
                 u->state = UPLOAD_WRITE_LOCAL;  
         }  
   
         /* Initialies our blocks. */          /* Initialies our blocks. */
   
         assert(u->state == UPLOAD_WRITE_LOCAL);          assert(u->state == UPLOAD_WRITE);
         memset(&blk, 0, sizeof(struct blkset));          memset(&blk, 0, sizeof(struct blkset));
         blk.csum = u->csumlen;          blk.csum = u->csumlen;
   
         if (*fileinfd != -1 && st.st_size > 0) {          if (*fileinfd != -1 && filesize > 0) {
                 init_blkset(&blk, st.st_size);                  init_blkset(&blk, filesize);
                 assert(blk.blksz);                  assert(blk.blksz);
   
                 blk.blks = calloc(blk.blksz, sizeof(struct blk));                  blk.blks = calloc(blk.blksz, sizeof(struct blk));
Line 918 
Line 987 
                         return -1;                          return -1;
                 }                  }
   
                 if ((mbuf = calloc(1, blk.len)) == NULL) {                  if ((mbuf = malloc(blk.len)) == NULL) {
                         ERR("calloc");                          ERR("malloc");
                         close(*fileinfd);                          close(*fileinfd);
                         *fileinfd = -1;                          *fileinfd = -1;
                           free(blk.blks);
                         return -1;                          return -1;
                 }                  }
   
Line 929 
Line 999 
                 i = 0;                  i = 0;
                 do {                  do {
                         msz = pread(*fileinfd, mbuf, blk.len, offs);                          msz = pread(*fileinfd, mbuf, blk.len, offs);
                         if (msz < 0) {                          if ((size_t)msz != blk.len && (size_t)msz != blk.rem) {
                                 ERR("pread");                                  ERR("pread");
                                 close(*fileinfd);                                  close(*fileinfd);
                                 *fileinfd = -1;                                  *fileinfd = -1;
                                   free(mbuf);
                                   free(blk.blks);
                                 return -1;                                  return -1;
                         }                          }
                         if ((size_t)msz != blk.len && (size_t)msz != blk.rem) {  
                                 /* short read, try again */  
                                 continue;  
                         }  
                         init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess);                          init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess);
                         offs += blk.len;                          offs += blk.len;
                         LOG3(                          LOG3(
Line 947 
Line 1015 
                         i++;                          i++;
                 } while (i < blk.blksz);                  } while (i < blk.blksz);
   
                   free(mbuf);
                 close(*fileinfd);                  close(*fileinfd);
                 *fileinfd = -1;                  *fileinfd = -1;
                 LOG3("%s: mapped %jd B with %zu blocks",                  LOG3("%s: mapped %jd B with %zu blocks",
Line 966 
Line 1035 
         /* Make sure the block metadata buffer is big enough. */          /* Make sure the block metadata buffer is big enough. */
   
         u->bufsz =          u->bufsz =
              sizeof(int32_t) + /* identifier */              sizeof(int32_t) + /* identifier */
              sizeof(int32_t) + /* block count */              sizeof(int32_t) + /* block count */
              sizeof(int32_t) + /* block length */              sizeof(int32_t) + /* block length */
              sizeof(int32_t) + /* checksum length */              sizeof(int32_t) + /* checksum length */
              sizeof(int32_t) + /* block remainder */              sizeof(int32_t) + /* block remainder */
              blk.blksz *              blk.blksz *
              (sizeof(int32_t) + /* short checksum */              (sizeof(int32_t) + /* short checksum */
               blk.csum); /* long checksum */              blk.csum); /* long checksum */
   
         if (u->bufsz > u->bufmax) {          if (u->bufsz > u->bufmax) {
                 if ((bufp = realloc(u->buf, u->bufsz)) == NULL) {                  if ((bufp = realloc(u->buf, u->bufsz)) == NULL) {
                         ERR("realloc");                          ERR("realloc");
                           free(blk.blks);
                         return -1;                          return -1;
                 }                  }
                 u->buf = bufp;                  u->buf = bufp;

Legend:
Removed from v.1.24  
changed lines
  Added in v.1.24.2.1