version 1.22, 2019/03/30 07:28:55 |
version 1.23, 2019/05/08 20:00:25 |
|
|
ts[1].tv_sec = f->st.mtime; |
ts[1].tv_sec = f->st.mtime; |
ts[1].tv_nsec = 0; |
ts[1].tv_nsec = 0; |
if (futimens(fd, ts) == -1) { |
if (futimens(fd, ts) == -1) { |
ERR(sess, "%s: futimens", path); |
ERR("%s: futimens", path); |
return 0; |
return 0; |
} |
} |
LOG4(sess, "%s: updated date", f->path); |
LOG4("%s: updated date", f->path); |
} |
} |
|
|
/* |
/* |
|
|
if (uid != (uid_t)-1 || gid != (gid_t)-1) { |
if (uid != (uid_t)-1 || gid != (gid_t)-1) { |
if (fchown(fd, uid, gid) == -1) { |
if (fchown(fd, uid, gid) == -1) { |
if (errno != EPERM) { |
if (errno != EPERM) { |
ERR(sess, "%s: fchown", path); |
ERR("%s: fchown", path); |
return 0; |
return 0; |
} |
} |
if (getuid() == 0) |
if (getuid() == 0) |
WARNX(sess, "%s: identity unknown or not available " |
WARNX("%s: identity unknown or not available " |
"to user.group: %u.%u", f->path, uid, gid); |
"to user.group: %u.%u", f->path, uid, gid); |
} else |
} else |
LOG4(sess, "%s: updated uid and/or gid", f->path); |
LOG4("%s: updated uid and/or gid", f->path); |
mode &= ~(S_ISTXT | S_ISUID | S_ISGID); |
mode &= ~(S_ISTXT | S_ISUID | S_ISGID); |
} |
} |
|
|
|
|
|
|
if (newfile || sess->opts->preserve_perms) { |
if (newfile || sess->opts->preserve_perms) { |
if (fchmod(fd, mode) == -1) { |
if (fchmod(fd, mode) == -1) { |
ERR(sess, "%s: fchmod", path); |
ERR("%s: fchmod", path); |
return 0; |
return 0; |
} |
} |
LOG4(sess, "%s: updated permissions", f->path); |
LOG4("%s: updated permissions", f->path); |
} |
} |
|
|
return 1; |
return 1; |
|
|
ts[1].tv_sec = f->st.mtime; |
ts[1].tv_sec = f->st.mtime; |
ts[1].tv_nsec = 0; |
ts[1].tv_nsec = 0; |
if (utimensat(rootfd, path, ts, AT_SYMLINK_NOFOLLOW) == -1) { |
if (utimensat(rootfd, path, ts, AT_SYMLINK_NOFOLLOW) == -1) { |
ERR(sess, "%s: utimensat", path); |
ERR("%s: utimensat", path); |
return 0; |
return 0; |
} |
} |
LOG4(sess, "%s: updated date", f->path); |
LOG4("%s: updated date", f->path); |
} |
} |
|
|
/* |
/* |
|
|
if (uid != (uid_t)-1 || gid != (gid_t)-1) { |
if (uid != (uid_t)-1 || gid != (gid_t)-1) { |
if (fchownat(rootfd, path, uid, gid, AT_SYMLINK_NOFOLLOW) == -1) { |
if (fchownat(rootfd, path, uid, gid, AT_SYMLINK_NOFOLLOW) == -1) { |
if (errno != EPERM) { |
if (errno != EPERM) { |
ERR(sess, "%s: fchownat", path); |
ERR("%s: fchownat", path); |
return 0; |
return 0; |
} |
} |
if (getuid() == 0) |
if (getuid() == 0) |
WARNX(sess, "%s: identity unknown or not available " |
WARNX("%s: identity unknown or not available " |
"to user.group: %u.%u", f->path, uid, gid); |
"to user.group: %u.%u", f->path, uid, gid); |
} else |
} else |
LOG4(sess, "%s: updated uid and/or gid", f->path); |
LOG4("%s: updated uid and/or gid", f->path); |
mode &= ~(S_ISTXT | S_ISUID | S_ISGID); |
mode &= ~(S_ISTXT | S_ISUID | S_ISGID); |
} |
} |
|
|
|
|
|
|
if (newfile || sess->opts->preserve_perms) { |
if (newfile || sess->opts->preserve_perms) { |
if (fchmodat(rootfd, path, mode, AT_SYMLINK_NOFOLLOW) == -1) { |
if (fchmodat(rootfd, path, mode, AT_SYMLINK_NOFOLLOW) == -1) { |
ERR(sess, "%s: fchmodat", path); |
ERR("%s: fchmodat", path); |
return 0; |
return 0; |
} |
} |
LOG4(sess, "%s: updated permissions", f->path); |
LOG4("%s: updated permissions", f->path); |
} |
} |
|
|
return 1; |
return 1; |
|
|
mode_t oumask; |
mode_t oumask; |
|
|
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) { |
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) { |
ERR(sess, "pledge"); |
ERR("pledge"); |
goto out; |
goto out; |
} |
} |
|
|
|
|
|
|
if (!sess->opts->server && |
if (!sess->opts->server && |
!io_write_int(sess, fdout, 0)) { |
!io_write_int(sess, fdout, 0)) { |
ERRX1(sess, "io_write_int"); |
ERRX1("io_write_int"); |
goto out; |
goto out; |
} |
} |
|
|
if (sess->opts->server && sess->opts->del) { |
if (sess->opts->server && sess->opts->del) { |
if (!io_read_size(sess, fdin, &excl)) { |
if (!io_read_size(sess, fdin, &excl)) { |
ERRX1(sess, "io_read_size"); |
ERRX1("io_read_size"); |
goto out; |
goto out; |
} else if (excl != 0) { |
} else if (excl != 0) { |
ERRX(sess, "exclusion list is non-empty"); |
ERRX("exclusion list is non-empty"); |
goto out; |
goto out; |
} |
} |
} |
} |
|
|
*/ |
*/ |
|
|
if (!flist_recv(sess, fdin, &fl, &flsz)) { |
if (!flist_recv(sess, fdin, &fl, &flsz)) { |
ERRX1(sess, "flist_recv"); |
ERRX1("flist_recv"); |
goto out; |
goto out; |
} |
} |
|
|
/* The IO error is sent after the file list. */ |
/* The IO error is sent after the file list. */ |
|
|
if (!io_read_int(sess, fdin, &ioerror)) { |
if (!io_read_int(sess, fdin, &ioerror)) { |
ERRX1(sess, "io_read_int"); |
ERRX1("io_read_int"); |
goto out; |
goto out; |
} else if (ioerror != 0) { |
} else if (ioerror != 0) { |
ERRX1(sess, "io_error is non-zero"); |
ERRX1("io_error is non-zero"); |
goto out; |
goto out; |
} |
} |
|
|
if (flsz == 0 && !sess->opts->server) { |
if (flsz == 0 && !sess->opts->server) { |
WARNX(sess, "receiver has empty file list: exiting"); |
WARNX("receiver has empty file list: exiting"); |
rc = 1; |
rc = 1; |
goto out; |
goto out; |
} else if (!sess->opts->server) |
} else if (!sess->opts->server) |
LOG1(sess, "Transfer starting: %zu files", flsz); |
LOG1("Transfer starting: %zu files", flsz); |
|
|
LOG2(sess, "%s: receiver destination", root); |
LOG2("%s: receiver destination", root); |
|
|
/* |
/* |
* Create the path for our destination directory, if we're not |
* Create the path for our destination directory, if we're not |
|
|
|
|
if (!sess->opts->dry_run) { |
if (!sess->opts->dry_run) { |
if ((tofree = strdup(root)) == NULL) { |
if ((tofree = strdup(root)) == NULL) { |
ERR(sess, "strdup"); |
ERR("strdup"); |
goto out; |
goto out; |
} else if (mkpath(sess, tofree) < 0) { |
} else if (mkpath(sess, tofree) < 0) { |
ERRX1(sess, "%s: mkpath", root); |
ERRX1("%s: mkpath", root); |
free(tofree); |
free(tofree); |
goto out; |
goto out; |
} |
} |
|
|
if (!sess->opts->dry_run) { |
if (!sess->opts->dry_run) { |
dfd = open(root, O_RDONLY | O_DIRECTORY, 0); |
dfd = open(root, O_RDONLY | O_DIRECTORY, 0); |
if (dfd == -1) { |
if (dfd == -1) { |
ERR(sess, "%s: open", root); |
ERR("%s: open", root); |
goto out; |
goto out; |
} |
} |
} |
} |
|
|
if (sess->opts->del && |
if (sess->opts->del && |
sess->opts->recursive && |
sess->opts->recursive && |
!flist_gen_dels(sess, root, &dfl, &dflsz, fl, flsz)) { |
!flist_gen_dels(sess, root, &dfl, &dflsz, fl, flsz)) { |
ERRX1(sess, "flist_gen_local"); |
ERRX1("flist_gen_local"); |
goto out; |
goto out; |
} |
} |
|
|
|
|
*/ |
*/ |
|
|
if (unveil(root, "rwc") == -1) { |
if (unveil(root, "rwc") == -1) { |
ERR(sess, "%s: unveil", root); |
ERR("%s: unveil", root); |
goto out; |
goto out; |
} else if (unveil(NULL, NULL) == -1) { |
} else if (unveil(NULL, NULL) == -1) { |
ERR(sess, "%s: unveil", root); |
ERR("%s: unveil", root); |
goto out; |
goto out; |
} |
} |
|
|
/* If we have a local set, go for the deletion. */ |
/* If we have a local set, go for the deletion. */ |
|
|
if (!flist_del(sess, dfd, dfl, dflsz)) { |
if (!flist_del(sess, dfd, dfl, dflsz)) { |
ERRX1(sess, "flist_del"); |
ERRX1("flist_del"); |
goto out; |
goto out; |
} |
} |
|
|
|
|
ul = upload_alloc(sess, root, dfd, fdout, |
ul = upload_alloc(sess, root, dfd, fdout, |
CSUM_LENGTH_PHASE1, fl, flsz, oumask); |
CSUM_LENGTH_PHASE1, fl, flsz, oumask); |
if (ul == NULL) { |
if (ul == NULL) { |
ERRX1(sess, "upload_alloc"); |
ERRX1("upload_alloc"); |
goto out; |
goto out; |
} |
} |
|
|
dl = download_alloc(sess, fdin, fl, flsz, dfd); |
dl = download_alloc(sess, fdin, fl, flsz, dfd); |
if (dl == NULL) { |
if (dl == NULL) { |
ERRX1(sess, "download_alloc"); |
ERRX1("download_alloc"); |
goto out; |
goto out; |
} |
} |
|
|
LOG2(sess, "%s: ready for phase 1 data", root); |
LOG2("%s: ready for phase 1 data", root); |
|
|
for (;;) { |
for (;;) { |
if ((c = poll(pfd, PFD__MAX, POLL_TIMEOUT)) == -1) { |
if ((c = poll(pfd, PFD__MAX, POLL_TIMEOUT)) == -1) { |
ERR(sess, "poll"); |
ERR("poll"); |
goto out; |
goto out; |
} else if (c == 0) { |
} else if (c == 0) { |
ERRX(sess, "poll: timeout"); |
ERRX("poll: timeout"); |
goto out; |
goto out; |
} |
} |
|
|
for (i = 0; i < PFD__MAX; i++) |
for (i = 0; i < PFD__MAX; i++) |
if (pfd[i].revents & (POLLERR|POLLNVAL)) { |
if (pfd[i].revents & (POLLERR|POLLNVAL)) { |
ERRX(sess, "poll: bad fd"); |
ERRX("poll: bad fd"); |
goto out; |
goto out; |
} else if (pfd[i].revents & POLLHUP) { |
} else if (pfd[i].revents & POLLHUP) { |
ERRX(sess, "poll: hangup"); |
ERRX("poll: hangup"); |
goto out; |
goto out; |
} |
} |
|
|
|
|
if (sess->mplex_reads && |
if (sess->mplex_reads && |
(POLLIN & pfd[PFD_SENDER_IN].revents)) { |
(POLLIN & pfd[PFD_SENDER_IN].revents)) { |
if (!io_read_flush(sess, fdin)) { |
if (!io_read_flush(sess, fdin)) { |
ERRX1(sess, "io_read_flush"); |
ERRX1("io_read_flush"); |
goto out; |
goto out; |
} else if (sess->mplex_read_remain == 0) |
} else if (sess->mplex_read_remain == 0) |
pfd[PFD_SENDER_IN].revents &= ~POLLIN; |
pfd[PFD_SENDER_IN].revents &= ~POLLIN; |
|
|
&pfd[PFD_UPLOADER_IN].fd, |
&pfd[PFD_UPLOADER_IN].fd, |
sess, &pfd[PFD_SENDER_OUT].fd); |
sess, &pfd[PFD_SENDER_OUT].fd); |
if (c < 0) { |
if (c < 0) { |
ERRX1(sess, "rsync_uploader"); |
ERRX1("rsync_uploader"); |
goto out; |
goto out; |
} |
} |
} |
} |
|
|
c = rsync_downloader(dl, sess, |
c = rsync_downloader(dl, sess, |
&pfd[PFD_DOWNLOADER_IN].fd); |
&pfd[PFD_DOWNLOADER_IN].fd); |
if (c < 0) { |
if (c < 0) { |
ERRX1(sess, "rsync_downloader"); |
ERRX1("rsync_downloader"); |
goto out; |
goto out; |
} else if (c == 0) { |
} else if (c == 0) { |
assert(phase == 0); |
assert(phase == 0); |
phase++; |
phase++; |
LOG2(sess, |
LOG2("%s: receiver ready for phase 2 data", root); |
"%s: receiver ready for phase 2 data", |
|
root); |
|
break; |
break; |
} |
} |
|
|
|
|
|
|
if (phase == 1) { |
if (phase == 1) { |
if (!io_write_int(sess, fdout, -1)) { |
if (!io_write_int(sess, fdout, -1)) { |
ERRX1(sess, "io_write_int"); |
ERRX1("io_write_int"); |
goto out; |
goto out; |
} else if (!io_read_int(sess, fdin, &ioerror)) { |
} else if (!io_read_int(sess, fdin, &ioerror)) { |
ERRX1(sess, "io_read_int"); |
ERRX1("io_read_int"); |
goto out; |
goto out; |
} else if (ioerror != -1) { |
} else if (ioerror != -1) { |
ERRX(sess, "expected phase ack"); |
ERRX("expected phase ack"); |
goto out; |
goto out; |
} |
} |
} |
} |
|
|
*/ |
*/ |
|
|
if (!rsync_uploader_tail(ul, sess)) { |
if (!rsync_uploader_tail(ul, sess)) { |
ERRX1(sess, "rsync_uploader_tail"); |
ERRX1("rsync_uploader_tail"); |
goto out; |
goto out; |
} |
} |
|
|
/* Process server statistics and say good-bye. */ |
/* Process server statistics and say good-bye. */ |
|
|
if (!sess_stats_recv(sess, fdin)) { |
if (!sess_stats_recv(sess, fdin)) { |
ERRX1(sess, "sess_stats_recv"); |
ERRX1("sess_stats_recv"); |
goto out; |
goto out; |
} else if (!io_write_int(sess, fdout, -1)) { |
} else if (!io_write_int(sess, fdout, -1)) { |
ERRX1(sess, "io_write_int"); |
ERRX1("io_write_int"); |
goto out; |
goto out; |
} |
} |
|
|
LOG2(sess, "receiver finished updating"); |
LOG2("receiver finished updating"); |
rc = 1; |
rc = 1; |
out: |
out: |
if (dfd != -1) |
if (dfd != -1) |