=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/rsync/uploader.c,v retrieving revision 1.24.2.1 retrieving revision 1.25 diff -c -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 **** ! /* $Id: uploader.c,v 1.24.2.1 2021/11/09 13:41:24 benno Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * Copyright (c) 2019 Florian Obser --- 1,4 ---- ! /* $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,25 **** #include #include - #include #include #include #include --- 19,24 ---- *************** *** 80,86 **** * operator that we're a link. */ static void ! log_symlink(struct sess *sess, const struct flist *f) { if (!sess->opts->server) --- 79,85 ---- * operator that we're a link. */ static void ! log_link(struct sess *sess, const struct flist *f) { if (!sess->opts->server) *************** *** 167,173 **** * Return <0 on failure 0 on success. */ static int ! pre_symlink(struct upload *p, struct sess *sess) { struct stat st; const struct flist *f; --- 166,172 ---- * Return <0 on failure 0 on success. */ static int ! pre_link(struct upload *p, struct sess *sess) { struct stat st; const struct flist *f; *************** *** 182,188 **** return 0; } if (sess->opts->dry_run) { ! log_symlink(sess, f); return 0; } --- 181,187 ---- return 0; } if (sess->opts->dry_run) { ! log_link(sess, f); return 0; } *************** *** 195,205 **** 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) { --- 194,199 ---- *************** *** 207,212 **** --- 201,209 ---- return -1; } rc = -1; + } else if (rc == -1 && errno != ENOENT) { + ERR("%s: fstatat", f->path); + return -1; } /* *************** *** 262,273 **** free(temp); } ! log_symlink(sess, f); return 0; } /* ! * See pre_symlink(), but for devices. * FIXME: this is very similar to the other pre_xxx() functions. * Return <0 on failure 0 on success. */ --- 259,270 ---- free(temp); } ! log_link(sess, f); return 0; } /* ! * 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,309 **** 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) { --- 297,302 ---- *************** *** 311,316 **** --- 304,312 ---- 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,362 **** } /* ! * See pre_symlink(), but for FIFOs. * FIXME: this is very similar to the other pre_xxx() functions. * Return <0 on failure 0 on success. */ --- 352,358 ---- } /* ! * 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,398 **** 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) { --- 385,390 ---- *************** *** 400,405 **** --- 392,400 ---- return -1; } rc = -1; + } else if (rc == -1 && errno != ENOENT) { + ERR("%s: fstatat", f->path); + return -1; } if (rc == -1) { *************** *** 433,439 **** } /* ! * See pre_symlink(), but for socket files. * FIXME: this is very similar to the other pre_xxx() functions. * Return <0 on failure 0 on success. */ --- 428,434 ---- } /* ! * 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,475 **** 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) { --- 461,466 ---- *************** *** 477,482 **** --- 468,476 ---- return -1; } rc = -1; + } else if (rc == -1 && errno != ENOENT) { + ERR("%s: fstatat", f->path); + return -1; } if (rc == -1) { *************** *** 539,546 **** if (rc == -1 && errno != ENOENT) { ERR("%s: fstatat", f->path); return -1; ! } ! if (rc != -1 && !S_ISDIR(st.st_mode)) { ERRX("%s: not a directory", f->path); return -1; } else if (rc != -1) { --- 533,539 ---- if (rc == -1 && errno != ENOENT) { ERR("%s: fstatat", f->path); return -1; ! } else if (rc != -1 && !S_ISDIR(st.st_mode)) { ERRX("%s: not a directory", f->path); return -1; } else if (rc != -1) { *************** *** 642,696 **** } /* - * 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, 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)); --- 635,650 ---- } /* * 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, struct stat *st, struct sess *sess) { const struct flist *f; f = &p->fl[p->idx]; assert(S_ISREG(f->st.mode)); *************** *** 704,791 **** 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. */ ! *size = 0; ! *filefd = -1; ! rc = check_file(p->rootfd, f, &st); ! if (rc == -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; } --- 658,711 ---- 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. */ ! *filefd = openat(p->rootfd, f->path, ! O_RDONLY | O_NOFOLLOW, 0); ! if (*filefd == -1 && errno != ENOENT) { ! ERR("%s: openat", f->path); return -1; } ! if (*filefd == -1) ! return 1; ! /* ! * Check if the file is already up to date, in which case close it ! * and go to the next one. ! */ ! 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 (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; } /* file needs attention */ return 1; } *************** *** 858,870 **** struct sess *sess, int *fileoutfd) { struct blkset blk; void *mbuf, *bufp; ssize_t msz; size_t i, pos, sz; ! off_t offs, filesize; int c; ! /* Once finished this should never get called again. */ assert(u->state != UPLOAD_FINISHED); /* --- 778,792 ---- 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; int c; ! /* This should never get called. */ ! assert(u->state != UPLOAD_FINISHED); /* *************** *** 928,936 **** 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); else if (S_ISREG(u->fl[u->idx].st.mode)) ! c = pre_file(u, fileinfd, &filesize, sess); else if (S_ISBLK(u->fl[u->idx].st.mode) || S_ISCHR(u->fl[u->idx].st.mode)) c = pre_dev(u, sess); --- 850,858 ---- 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_link(u, sess); else if (S_ISREG(u->fl[u->idx].st.mode)) ! 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,982 **** memset(&blk, 0, sizeof(struct blkset)); blk.csum = u->csumlen; ! if (*fileinfd != -1 && filesize > 0) { ! init_blkset(&blk, filesize); assert(blk.blksz); blk.blks = calloc(blk.blksz, sizeof(struct blk)); --- 897,904 ---- memset(&blk, 0, sizeof(struct blkset)); blk.csum = u->csumlen; ! 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,997 **** ERR("malloc"); close(*fileinfd); *fileinfd = -1; - free(blk.blks); return -1; } --- 913,918 ---- *************** *** 1004,1010 **** close(*fileinfd); *fileinfd = -1; free(mbuf); - free(blk.blks); return -1; } init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess); --- 925,930 ---- *************** *** 1035,1053 **** /* 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 */ if (u->bufsz > u->bufmax) { if ((bufp = realloc(u->buf, u->bufsz)) == NULL) { ERR("realloc"); - free(blk.blks); return -1; } u->buf = bufp; --- 955,972 ---- /* 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 */ if (u->bufsz > u->bufmax) { if ((bufp = realloc(u->buf, u->bufsz)) == NULL) { ERR("realloc"); return -1; } u->buf = bufp;