=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/rsync/uploader.c,v retrieving revision 1.24.2.1 retrieving revision 1.25 diff -u -r1.24.2.1 -r1.25 --- src/usr.bin/rsync/uploader.c 2021/11/09 13:41:24 1.24.2.1 +++ src/usr.bin/rsync/uploader.c 2021/05/06 07:35:22 1.25 @@ -1,4 +1,4 @@ -/* $Id: uploader.c,v 1.24.2.1 2021/11/09 13:41:24 benno Exp $ */ +/* $Id: uploader.c,v 1.25 2021/05/06 07:35:22 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * Copyright (c) 2019 Florian Obser @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -80,7 +79,7 @@ * operator that we're a link. */ static void -log_symlink(struct sess *sess, const struct flist *f) +log_link(struct sess *sess, const struct flist *f) { if (!sess->opts->server) @@ -167,7 +166,7 @@ * Return <0 on failure 0 on success. */ static int -pre_symlink(struct upload *p, struct sess *sess) +pre_link(struct upload *p, struct sess *sess) { struct stat st; const struct flist *f; @@ -182,7 +181,7 @@ return 0; } if (sess->opts->dry_run) { - log_symlink(sess, f); + log_link(sess, f); return 0; } @@ -195,11 +194,6 @@ 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) { @@ -207,6 +201,9 @@ return -1; } rc = -1; + } else if (rc == -1 && errno != ENOENT) { + ERR("%s: fstatat", f->path); + return -1; } /* @@ -262,12 +259,12 @@ free(temp); } - log_symlink(sess, f); + log_link(sess, f); return 0; } /* - * See pre_symlink(), but for devices. + * See pre_link(), but for devices. * FIXME: this is very similar to the other pre_xxx() functions. * Return <0 on failure 0 on success. */ @@ -300,10 +297,6 @@ 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) { @@ -311,6 +304,9 @@ 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. */ @@ -356,7 +352,7 @@ } /* - * See pre_symlink(), but for FIFOs. + * See pre_link(), but for FIFOs. * FIXME: this is very similar to the other pre_xxx() functions. * Return <0 on failure 0 on success. */ @@ -389,10 +385,6 @@ 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) { @@ -400,6 +392,9 @@ return -1; } rc = -1; + } else if (rc == -1 && errno != ENOENT) { + ERR("%s: fstatat", f->path); + return -1; } if (rc == -1) { @@ -433,7 +428,7 @@ } /* - * See pre_symlink(), but for socket files. + * See pre_link(), but for socket files. * FIXME: this is very similar to the other pre_xxx() functions. * Return <0 on failure 0 on success. */ @@ -466,10 +461,6 @@ 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) { @@ -477,6 +468,9 @@ return -1; } rc = -1; + } else if (rc == -1 && errno != ENOENT) { + ERR("%s: fstatat", f->path); + return -1; } if (rc == -1) { @@ -539,8 +533,7 @@ if (rc == -1 && errno != ENOENT) { ERR("%s: fstatat", f->path); return -1; - } - if (rc != -1 && !S_ISDIR(st.st_mode)) { + } else if (rc != -1 && !S_ISDIR(st.st_mode)) { ERRX("%s: not a directory", f->path); return -1; } else if (rc != -1) { @@ -642,55 +635,16 @@ } /* - * 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. * If the file does not exist, returns with >0. * Return <0 on failure, 0 on success w/nothing to be done, >0 on * success and the file needs attention. */ static int -pre_file(const struct upload *p, int *filefd, off_t *size, +pre_file(const struct upload *p, int *filefd, struct stat *st, struct sess *sess) { const struct flist *f; - struct stat st; - int i, rc, match = -1; f = &p->fl[p->idx]; assert(S_ISREG(f->st.mode)); @@ -704,88 +658,54 @@ 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 * in the rsync_uploader() function. + * If the call to openat() fails with ENOENT, there's a + * fast-path between here and the write function. */ - *size = 0; - *filefd = -1; + *filefd = openat(p->rootfd, f->path, + O_RDONLY | O_NOFOLLOW, 0); - rc = check_file(p->rootfd, f, &st); - if (rc == -1) + if (*filefd == -1 && errno != ENOENT) { + ERR("%s: openat", f->path); 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; - } + if (*filefd == -1) + return 1; - /* 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; + /* + * Check if the file is already up to date, in which case close it + * and go to the next one. + */ - 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 (fstat(*filefd, st) == -1) { + ERR("%s: fstat", f->path); + close(*filefd); + *filefd = -1; + return -1; + } else if (!S_ISREG(st->st_mode)) { + ERRX("%s: not regular", f->path); + close(*filefd); + *filefd = -1; + return -1; } - 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); + + 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); + *filefd = -1; return -1; } + close(*filefd); + *filefd = -1; + return 0; } - *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; } @@ -858,13 +778,15 @@ struct sess *sess, int *fileoutfd) { struct blkset blk; + struct stat st; void *mbuf, *bufp; ssize_t msz; size_t i, pos, sz; - off_t offs, filesize; + off_t offs; int c; - /* Once finished this should never get called again. */ + /* This should never get called. */ + assert(u->state != UPLOAD_FINISHED); /* @@ -928,9 +850,9 @@ if (S_ISDIR(u->fl[u->idx].st.mode)) c = pre_dir(u, sess); else if (S_ISLNK(u->fl[u->idx].st.mode)) - c = pre_symlink(u, sess); + c = pre_link(u, sess); else if (S_ISREG(u->fl[u->idx].st.mode)) - c = pre_file(u, fileinfd, &filesize, sess); + c = pre_file(u, fileinfd, &st, sess); else if (S_ISBLK(u->fl[u->idx].st.mode) || S_ISCHR(u->fl[u->idx].st.mode)) c = pre_dev(u, sess); @@ -975,8 +897,8 @@ memset(&blk, 0, sizeof(struct blkset)); blk.csum = u->csumlen; - if (*fileinfd != -1 && filesize > 0) { - init_blkset(&blk, filesize); + if (*fileinfd != -1 && st.st_size > 0) { + init_blkset(&blk, st.st_size); assert(blk.blksz); blk.blks = calloc(blk.blksz, sizeof(struct blk)); @@ -991,7 +913,6 @@ ERR("malloc"); close(*fileinfd); *fileinfd = -1; - free(blk.blks); return -1; } @@ -1004,7 +925,6 @@ close(*fileinfd); *fileinfd = -1; free(mbuf); - free(blk.blks); return -1; } init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess); @@ -1035,19 +955,18 @@ /* Make sure the block metadata buffer is big enough. */ u->bufsz = - sizeof(int32_t) + /* identifier */ - sizeof(int32_t) + /* block count */ - sizeof(int32_t) + /* block length */ - sizeof(int32_t) + /* checksum length */ - sizeof(int32_t) + /* block remainder */ - blk.blksz * - (sizeof(int32_t) + /* short checksum */ - blk.csum); /* long checksum */ + sizeof(int32_t) + /* identifier */ + sizeof(int32_t) + /* block count */ + sizeof(int32_t) + /* block length */ + sizeof(int32_t) + /* checksum length */ + sizeof(int32_t) + /* block remainder */ + blk.blksz * + (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;