As noticed by benno@ the blk.blks buffer is leaked in some cases. Fix those and cleanup up the pre_* functions a bit more. I increased the diff context a bit to make the diff easier to read.
-- :wq Claudio Index: uploader.c =================================================================== RCS file: /cvs/src/usr.bin/rsync/uploader.c,v retrieving revision 1.25 diff -u -p -U6 -r1.25 uploader.c --- uploader.c 6 May 2021 07:35:22 -0000 1.25 +++ uploader.c 6 May 2021 15:34:36 -0000 @@ -191,22 +191,24 @@ pre_link(struct upload *p, struct sess * * to overwriting with a symbolic link. * If it's a non-directory, we just overwrite it. */ assert(p->rootfd != -1); 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 (S_ISDIR(st.st_mode) && unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { ERR("%s: unlinkat", f->path); return -1; } rc = -1; - } else if (rc == -1 && errno != ENOENT) { - ERR("%s: fstatat", f->path); - return -1; } /* * If the symbolic link already exists, then make sure that it * points to the correct place. */ @@ -294,22 +296,23 @@ pre_dev(struct upload *p, struct sess *s * If it replaces a directory, remove the directory first. */ assert(p->rootfd != -1); 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 (S_ISDIR(st.st_mode) && unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { ERR("%s: unlinkat", f->path); return -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. */ if (rc != -1) { if ((f->st.mode & (S_IFCHR|S_IFBLK)) != @@ -382,22 +385,23 @@ pre_fifo(struct upload *p, struct sess * * mark it from replacement. */ assert(p->rootfd != -1); 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 (S_ISDIR(st.st_mode) && unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { ERR("%s: unlinkat", f->path); return -1; } rc = -1; - } else if (rc == -1 && errno != ENOENT) { - ERR("%s: fstatat", f->path); - return -1; } if (rc == -1) { newfifo = 1; if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { ERRX1("mktemplate"); @@ -458,22 +462,23 @@ pre_sock(struct upload *p, struct sess * * mark it from replacement. */ assert(p->rootfd != -1); 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 (S_ISDIR(st.st_mode) && unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) { ERR("%s: unlinkat", f->path); return -1; } rc = -1; - } else if (rc == -1 && errno != ENOENT) { - ERR("%s: fstatat", f->path); - return -1; } if (rc == -1) { newsock = 1; if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) { ERRX1("mktemplate"); @@ -530,13 +535,14 @@ pre_dir(const struct upload *p, struct s assert(p->rootfd != -1); rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW); if (rc == -1 && errno != ENOENT) { ERR("%s: fstatat", f->path); 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); return -1; } else if (rc != -1) { /* * FIXME: we should fchmod the permissions here as well, * as we may locally have shut down writing into the @@ -682,19 +688,21 @@ pre_file(const struct upload *p, int *fi if (fstat(*filefd, st) == -1) { ERR("%s: fstat", f->path); close(*filefd); *filefd = -1; return -1; - } else if (!S_ISREG(st->st_mode)) { + } + if (!S_ISREG(st->st_mode)) { ERRX("%s: not regular", f->path); close(*filefd); *filefd = -1; return -1; } + /* quick check if file is the same */ 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, *filefd, f, f->path)) { ERRX1("rsync_set_metadata"); close(*filefd); @@ -910,24 +918,26 @@ rsync_uploader(struct upload *u, int *fi } if ((mbuf = malloc(blk.len)) == NULL) { ERR("malloc"); close(*fileinfd); *fileinfd = -1; + free(blk.blks); return -1; } offs = 0; i = 0; do { msz = pread(*fileinfd, mbuf, blk.len, offs); if ((size_t)msz != blk.len && (size_t)msz != blk.rem) { ERR("pread"); close(*fileinfd); *fileinfd = -1; free(mbuf); + free(blk.blks); return -1; } init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess); offs += blk.len; LOG3( "i=%ld, offs=%lld, msz=%ld, blk.len=%lu, blk.rem=%lu", @@ -964,12 +974,13 @@ rsync_uploader(struct upload *u, int *fi (sizeof(int32_t) + /* short checksum */ blk.csum); /* long checksum */ if (u->bufsz > u->bufmax) { if ((bufp = realloc(u->buf, u->bufsz)) == NULL) { ERR("realloc"); + free(blk.blks); return -1; } u->buf = bufp; u->bufmax = u->bufsz; }