diff options
-rw-r--r-- | usr.bin/rsync/Makefile | 10 | ||||
-rw-r--r-- | usr.bin/rsync/copy.c | 90 | ||||
-rw-r--r-- | usr.bin/rsync/extern.h | 18 | ||||
-rw-r--r-- | usr.bin/rsync/fargs.c | 29 | ||||
-rw-r--r-- | usr.bin/rsync/main.c | 61 | ||||
-rw-r--r-- | usr.bin/rsync/receiver.c | 67 | ||||
-rw-r--r-- | usr.bin/rsync/rsync.1 | 17 | ||||
-rw-r--r-- | usr.bin/rsync/uploader.c | 126 |
8 files changed, 345 insertions, 73 deletions
diff --git a/usr.bin/rsync/Makefile b/usr.bin/rsync/Makefile index f2e4d460c57..74d15d29a64 100644 --- a/usr.bin/rsync/Makefile +++ b/usr.bin/rsync/Makefile @@ -1,14 +1,18 @@ -# $OpenBSD: Makefile,v 1.11 2021/08/29 13:43:46 claudio Exp $ +# $OpenBSD: Makefile,v 1.12 2021/10/22 11:10:34 claudio Exp $ PROG= openrsync -SRCS= blocks.c client.c downloader.c fargs.c flist.c hash.c ids.c \ +SRCS= blocks.c client.c copy.c downloader.c fargs.c flist.c hash.c ids.c \ io.c log.c main.c misc.c mkpath.c mktemp.c receiver.c rmatch.c \ rules.c sender.c server.c session.c socket.c symlinks.c uploader.c LDADD+= -lcrypto -lm DPADD+= ${LIBCRYPTO} ${LIBM} MAN= openrsync.1 -CFLAGS+=-g -W -Wall -Wextra +CFLAGS+= -Wall -Wextra +CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes +CFLAGS+= -Wmissing-declarations +CFLAGS+= -Wshadow + openrsync.1: rsync.1 ln -sf ${.CURDIR}/rsync.1 openrsync.1 diff --git a/usr.bin/rsync/copy.c b/usr.bin/rsync/copy.c new file mode 100644 index 00000000000..737234d2269 --- /dev/null +++ b/usr.bin/rsync/copy.c @@ -0,0 +1,90 @@ +/* $OpenBSD: copy.c,v 1.1 2021/10/22 11:10:34 claudio Exp $ */ +/* + * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> /* MAXBSIZE */ + +#include <err.h> +#include <fcntl.h> +#include <unistd.h> + +#include "extern.h" + +/* + * Return true if all bytes in buffer are zero. + * A buffer of zero lenght is also considered a zero buffer. + */ +static int +iszero(const void *b, size_t len) +{ + const unsigned char *c = b; + + for (; len > 0; len--) { + if (*c++ != '\0') + return 0; + } + return 1; +} + +static int +copy_internal(int fromfd, int tofd) +{ + char buf[MAXBSIZE]; + ssize_t r, w; + + while ((r = read(fromfd, buf, sizeof(buf))) > 0) { + if (iszero(buf, sizeof(buf))) { + if (lseek(tofd, r, SEEK_CUR) == -1) + return -1; + } else { + w = write(tofd, buf, r); + if (r != w || w == -1) + return -1; + } + } + if (r == -1) + return -1; + if (ftruncate(tofd, lseek(tofd, 0, SEEK_CUR)) == -1) + return -1; + return 0; +} + +void +copy_file(int rootfd, const char *basedir, const struct flist *f) +{ + int fromfd, tofd, dfd; + + dfd = openat(rootfd, basedir, O_RDONLY | O_DIRECTORY, 0); + if (dfd == -1) + err(ERR_FILE_IO, "%s: openat", basedir); + + fromfd = openat(dfd, f->path, O_RDONLY | O_NOFOLLOW, 0); + if (fromfd == -1) + err(ERR_FILE_IO, "%s/%s: openat", basedir, f->path); + close(dfd); + + tofd = openat(rootfd, f->path, + O_WRONLY | O_NOFOLLOW | O_TRUNC | O_CREAT | O_EXCL, + 0600); + if (tofd == -1) + err(ERR_FILE_IO, "%s: openat", f->path); + + if (copy_internal(fromfd, tofd) == -1) + err(ERR_FILE_IO, "%s: copy file", f->path); + + close(fromfd); + close(tofd); +} diff --git a/usr.bin/rsync/extern.h b/usr.bin/rsync/extern.h index 2815f82cf89..cd7006a1737 100644 --- a/usr.bin/rsync/extern.h +++ b/usr.bin/rsync/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.41 2021/09/01 09:48:08 claudio Exp $ */ +/* $OpenBSD: extern.h,v 1.42 2021/10/22 11:10:34 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -34,6 +34,15 @@ #define BLOCK_SIZE_MIN (700) /* + * Maximum number of base directories that can be used. + */ +#define MAX_BASEDIR 20 + +#define BASE_MODE_COMPARE 1 +#define BASE_MODE_COPY 2 +#define BASE_MODE_LINK 3 + +/* * The sender and receiver use a two-phase synchronisation process. * The first uses two-byte hashes; the second, 16-byte. * (The second must hold a full MD4 digest.) @@ -131,10 +140,12 @@ struct opts { int no_motd; /* --no-motd */ int numeric_ids; /* --numeric-ids */ int one_file_system; /* -x */ + int alt_base_mode; char *rsync_path; /* --rsync-path */ char *ssh_prog; /* --rsh or -e */ char *port; /* --port */ char *address; /* --address */ + char *basedir[MAX_BASEDIR]; }; enum rule_type { @@ -298,7 +309,8 @@ int flist_send(struct sess *, int, int, const struct flist *, size_t); int flist_gen_dels(struct sess *, const char *, struct flist **, size_t *, const struct flist *, size_t); -char **fargs_cmdline(struct sess *, const struct fargs *, size_t *); +const char *alt_base_mode(int); +char **fargs_cmdline(struct sess *, const struct fargs *, size_t *); int io_read_buf(struct sess *, int, void *, size_t); int io_read_byte(struct sess *, int, uint8_t *); @@ -368,6 +380,8 @@ void hash_slow(const void *, size_t, unsigned char *, void hash_file(const void *, size_t, unsigned char *, const struct sess *); +void copy_file(int, const char *, const struct flist *); + int mkpath(char *); int mkstempat(int, char *); diff --git a/usr.bin/rsync/fargs.c b/usr.bin/rsync/fargs.c index 4047416854b..a69955c4332 100644 --- a/usr.bin/rsync/fargs.c +++ b/usr.bin/rsync/fargs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fargs.c,v 1.19 2021/06/30 13:10:04 claudio Exp $ */ +/* $OpenBSD: fargs.c,v 1.20 2021/10/22 11:10:34 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -26,6 +26,21 @@ #define RSYNC_PATH "rsync" +const char * +alt_base_mode(int mode) +{ + switch(mode) { + case BASE_MODE_COMPARE: + return "--compare-dest"; + case BASE_MODE_COPY: + return "--copy-dest"; + case BASE_MODE_LINK: + return "--link-dest"; + default: + errx(1, "unknown base mode %d", mode); + } +} + char ** fargs_cmdline(struct sess *sess, const struct fargs *f, size_t *skip) { @@ -117,6 +132,18 @@ fargs_cmdline(struct sess *sess, const struct fargs *f, size_t *skip) /* --devices is sent as -D --no-specials */ addargs(&args, "--no-specials"); + /* only add --compare-dest, etc if this is the sender */ + if (sess->opts->alt_base_mode != 0 && + f->mode == FARGS_SENDER) { + for (j = 0; j < MAX_BASEDIR; j++) { + if (sess->opts->basedir[j] == NULL) + break; + addargs(&args, "%s=%s", + alt_base_mode(sess->opts->alt_base_mode), + sess->opts->basedir[j]); + } + } + /* Terminate with a full-stop for reasons unknown. */ addargs(&args, "."); diff --git a/usr.bin/rsync/main.c b/usr.bin/rsync/main.c index 06606c07674..70ae1e3ce30 100644 --- a/usr.bin/rsync/main.c +++ b/usr.bin/rsync/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.59 2021/09/01 09:48:08 claudio Exp $ */ +/* $OpenBSD: main.c,v 1.60 2021/10/22 11:10:34 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -280,10 +280,18 @@ static struct opts opts; #define OP_INCLUDE 1006 #define OP_EXCLUDE_FROM 1007 #define OP_INCLUDE_FROM 1008 +#define OP_COMP_DEST 1009 +#define OP_COPY_DEST 1010 +#define OP_LINK_DEST 1011 const struct option lopts[] = { { "address", required_argument, NULL, OP_ADDRESS }, { "archive", no_argument, NULL, 'a' }, + { "compare-dest", required_argument, NULL, OP_COMP_DEST }, +#if 0 + { "copy-dest", required_argument, NULL, OP_COPY_DEST }, + { "link-dest", required_argument, NULL, OP_LINK_DEST }, +#endif { "compress", no_argument, NULL, 'z' }, { "del", no_argument, &opts.del, 1 }, { "delete", no_argument, &opts.del, 1 }, @@ -327,7 +335,8 @@ int main(int argc, char *argv[]) { pid_t child; - int fds[2], sd = -1, rc, c, st, i; + int fds[2], sd = -1, rc, c, st, i, lidx; + size_t basedir_cnt = 0; struct sess sess; struct fargs *fargs; char **args; @@ -339,7 +348,7 @@ main(int argc, char *argv[]) NULL) == -1) err(ERR_IPC, "pledge"); - while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvxz", lopts, NULL)) + while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvxz", lopts, &lidx)) != -1) { switch (c) { case 'D': @@ -423,6 +432,41 @@ main(int argc, char *argv[]) case OP_INCLUDE_FROM: parse_file(optarg, RULE_INCLUDE); break; + case OP_COMP_DEST: + if (opts.alt_base_mode !=0 && + opts.alt_base_mode != BASE_MODE_COMPARE) { + errx(1, "option --%s conflicts with %s", + lopts[lidx].name, + alt_base_mode(opts.alt_base_mode)); + } + opts.alt_base_mode = BASE_MODE_COMPARE; +#if 0 + goto basedir; + case OP_COPY_DEST: + if (opts.alt_base_mode !=0 && + opts.alt_base_mode != BASE_MODE_COPY) { + errx(1, "option --%s conflicts with %s", + lopts[lidx].name, + alt_base_mode(opts.alt_base_mode)); + } + opts.alt_base_mode = BASE_MODE_COPY; + goto basedir; + case OP_LINK_DEST: + if (opts.alt_base_mode !=0 && + opts.alt_base_mode != BASE_MODE_LINK) { + errx(1, "option --%s conflicts with %s", + lopts[lidx].name, + alt_base_mode(opts.alt_base_mode)); + } + opts.alt_base_mode = BASE_MODE_LINK; + +basedir: +#endif + if (basedir_cnt >= MAX_BASEDIR) + errx(1, "too many --%s directories specified", + lopts[lidx].name); + opts.basedir[basedir_cnt++] = optarg; + break; case OP_VERSION: fprintf(stderr, "openrsync: protocol version %u\n", RSYNC_PROTOCOL); @@ -554,12 +598,11 @@ main(int argc, char *argv[]) exit(rc); usage: fprintf(stderr, "usage: %s" - " [-aDglnoprtvx] [-e program] [--address=sourceaddr] [--del]\n" - "\t[--exclude] [--exclude-from=file] [--include] " - "[--include-from=file]\n" - "\t[--no-motd] [--numeric-ids] [--port=portnumber] " - "[--rsync-path=program]\n\t[--timeout=seconds] [--version] " - "source ... directory\n", + " [-aDglnoprtvx] [-e program] [--address=sourceaddr]\n" + "\t[--compare-dest=dir] [--del] [--exclude] [--exclude-from=file]\n" + "\t[--include] [--include-from=file] [--no-motd] [--numeric-ids]\n" + "\t[--port=portnumber] [--rsync-path=program] [--timeout=seconds]\n" + "\t[--version] source ... directory\n", getprogname()); exit(ERR_SYNTAX); } diff --git a/usr.bin/rsync/receiver.c b/usr.bin/rsync/receiver.c index 6e5b01670cd..02e1a58d7c4 100644 --- a/usr.bin/rsync/receiver.c +++ b/usr.bin/rsync/receiver.c @@ -1,4 +1,4 @@ -/* $OpenBSD: receiver.c,v 1.29 2021/08/29 13:43:46 claudio Exp $ */ +/* $OpenBSD: receiver.c,v 1.30 2021/10/22 11:10:34 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> @@ -184,6 +184,44 @@ rsync_receiver(struct sess *sess, int fdin, int fdout, const char *root) if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) err(ERR_IPC, "pledge"); + /* + * Create the path for our destination directory, if we're not + * in dry-run mode (which would otherwise crash w/the pledge). + * This uses our current umask: we might set the permissions on + * this directory in post_dir(). + */ + + if (!sess->opts->dry_run) { + if ((tofree = strdup(root)) == NULL) + err(ERR_NOMEM, NULL); + if (mkpath(tofree) < 0) + err(ERR_FILE_IO, "%s: mkpath", tofree); + free(tofree); + } + + /* + * Make our entire view of the file-system be limited to what's + * in the root directory. + * This prevents us from accidentally (or "under the influence") + * writing into other parts of the file-system. + */ + if (sess->opts->basedir[0]) { + /* + * XXX just unveil everything for read + * Could unveil each basedir or maybe a common path + * also the fact that relative path are relative to the + * root does not help. + */ + if (unveil("/", "r") == -1) + err(ERR_IPC, "%s: unveil", root); + } + + if (unveil(root, "rwc") == -1) + err(ERR_IPC, "%s: unveil", root); + + if (unveil(NULL, NULL) == -1) + err(ERR_IPC, "unveil"); + /* Client sends exclusions. */ if (!sess->opts->server) send_rules(sess, fdout); @@ -222,21 +260,6 @@ rsync_receiver(struct sess *sess, int fdin, int fdout, const char *root) LOG2("%s: receiver destination", root); /* - * Create the path for our destination directory, if we're not - * in dry-run mode (which would otherwise crash w/the pledge). - * This uses our current umask: we might set the permissions on - * this directory in post_dir(). - */ - - if (!sess->opts->dry_run) { - if ((tofree = strdup(root)) == NULL) - err(ERR_NOMEM, NULL); - if (mkpath(tofree) < 0) - err(ERR_FILE_IO, "%s: mkpath", tofree); - free(tofree); - } - - /* * Disable umask() so we can set permissions fully. * Then open the directory iff we're not in dry_run. */ @@ -261,18 +284,6 @@ rsync_receiver(struct sess *sess, int fdin, int fdout, const char *root) goto out; } - /* - * Make our entire view of the file-system be limited to what's - * in the root directory. - * This prevents us from accidentally (or "under the influence") - * writing into other parts of the file-system. - */ - - if (unveil(root, "rwc") == -1) - err(ERR_IPC, "%s: unveil", root); - if (unveil(NULL, NULL) == -1) - err(ERR_IPC, "unveil"); - /* If we have a local set, go for the deletion. */ if (!flist_del(sess, dfd, dfl, dflsz)) { diff --git a/usr.bin/rsync/rsync.1 b/usr.bin/rsync/rsync.1 index 06d4ec606d6..9fcee4bdfbc 100644 --- a/usr.bin/rsync/rsync.1 +++ b/usr.bin/rsync/rsync.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rsync.1,v 1.25 2021/08/30 20:25:24 job Exp $ +.\" $OpenBSD: rsync.1,v 1.26 2021/10/22 11:10:34 claudio Exp $ .\" .\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 30 2021 $ +.Dd $Mdocdate: October 22 2021 $ .Dt OPENRSYNC 1 .Os .Sh NAME @@ -25,6 +25,7 @@ .Op Fl aDglnoprtvx .Op Fl e Ar program .Op Fl -address Ns = Ns Ar sourceaddr +.Op Fl -compare-dest Ns = Ns Ar directory .Op Fl -del .Op Fl -exclude Ar pattern .Op Fl -exclude-from Ns = Ns Ar file @@ -62,6 +63,18 @@ When connecting to an rsync daemon, use .Ar sourceaddr as the source address for connections, which is useful on machines with multiple interfaces. +.It Fl -compare-dest Ns = Ns Ar directory +Use directory as an alternate base directory to compare files against on the +destination machine. +If file in +.Ar directory +is found and identical to the senders file the file will not be transferred. +Multiple +.Fl -compare-dest +directories may be provided. +If +.Ar directory +is a relative path, it is relative to the destination directory. .It Fl D Also transfer device and special files. Shorthand for diff --git a/usr.bin/rsync/uploader.c b/usr.bin/rsync/uploader.c index e57647c38e5..254e1be0791 100644 --- a/usr.bin/rsync/uploader.c +++ b/usr.bin/rsync/uploader.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uploader.c,v 1.29 2021/06/30 13:10:04 claudio Exp $ */ +/* $OpenBSD: uploader.c,v 1.30 2021/10/22 11:10:34 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2019 Florian Obser <florian@openbsd.org> @@ -19,6 +19,7 @@ #include <sys/stat.h> #include <assert.h> +#include <err.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> @@ -166,7 +167,7 @@ init_blk(struct blk *p, const struct blkset *set, off_t offs, * Return <0 on failure 0 on success. */ static int -pre_link(struct upload *p, struct sess *sess) +pre_symlink(struct upload *p, struct sess *sess) { struct stat st; const struct flist *f; @@ -266,7 +267,7 @@ pre_link(struct upload *p, struct sess *sess) } /* - * See pre_link(), but for devices. + * See pre_symlink(), but for devices. * FIXME: this is very similar to the other pre_xxx() functions. * Return <0 on failure 0 on success. */ @@ -355,7 +356,7 @@ pre_dev(struct upload *p, struct sess *sess) } /* - * See pre_link(), but for FIFOs. + * See pre_symlink(), but for FIFOs. * FIXME: this is very similar to the other pre_xxx() functions. * Return <0 on failure 0 on success. */ @@ -432,7 +433,7 @@ pre_fifo(struct upload *p, struct sess *sess) } /* - * 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. * Return <0 on failure 0 on success. */ @@ -641,17 +642,55 @@ post_dir(struct sess *sess, const struct upload *u, size_t idx) } /* + * 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, struct stat *st, +pre_file(const struct upload *p, int *filefd, off_t *size, struct sess *sess) { const struct flist *f; - int rc; + struct stat st; + int i, rc, match = -1; f = &p->fl[p->idx]; assert(S_ISREG(f->st.mode)); @@ -670,36 +709,68 @@ pre_file(const struct upload *p, int *filefd, struct stat *st, * in the rsync_uploader() function. */ + *size = 0; *filefd = -1; - rc = fstatat(p->rootfd, f->path, st, AT_SYMLINK_NOFOLLOW); - if (rc == -1) { - if (errno == ENOENT) - return 1; - - ERR("%s: fstatat", f->path); + rc = check_file(p->rootfd, f, &st); + if (rc == -1) return -1; - } - if (!S_ISREG(st->st_mode)) { - if (S_ISDIR(st->st_mode) && + 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; } - 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 (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, 0); + 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, 0); if (*filefd == -1 && errno != ENOENT) { ERR("%s: openat", f->path); @@ -778,11 +849,10 @@ rsync_uploader(struct upload *u, int *fileinfd, 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; + off_t offs, filesize; int c; /* Once finished this should never get called again. */ @@ -849,9 +919,9 @@ rsync_uploader(struct upload *u, int *fileinfd, 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); + c = pre_symlink(u, sess); else if (S_ISREG(u->fl[u->idx].st.mode)) - c = pre_file(u, fileinfd, &st, sess); + 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); @@ -896,8 +966,8 @@ rsync_uploader(struct upload *u, int *fileinfd, memset(&blk, 0, sizeof(struct blkset)); blk.csum = u->csumlen; - if (*fileinfd != -1 && st.st_size > 0) { - init_blkset(&blk, st.st_size); + if (*fileinfd != -1 && filesize > 0) { + init_blkset(&blk, filesize); assert(blk.blksz); blk.blks = calloc(blk.blksz, sizeof(struct blk)); |