version 1.24, 2021/03/22 11:20:04 |
version 1.25, 2021/05/06 07:35:22 |
|
|
|
|
enum uploadst { |
enum uploadst { |
UPLOAD_FIND_NEXT = 0, /* find next to upload to sender */ |
UPLOAD_FIND_NEXT = 0, /* find next to upload to sender */ |
UPLOAD_WRITE_LOCAL, /* wait to write to sender */ |
UPLOAD_WRITE, /* wait to write to sender */ |
UPLOAD_READ_LOCAL, /* wait to read from local file */ |
|
UPLOAD_FINISHED /* nothing more to do in phase */ |
UPLOAD_FINISHED /* nothing more to do in phase */ |
}; |
}; |
|
|
|
|
if (!sess->opts->preserve_links) { |
if (!sess->opts->preserve_links) { |
WARNX("%s: ignoring symlink", f->path); |
WARNX("%s: ignoring symlink", f->path); |
return 0; |
return 0; |
} else if (sess->opts->dry_run) { |
} |
|
if (sess->opts->dry_run) { |
log_link(sess, f); |
log_link(sess, f); |
return 0; |
return 0; |
} |
} |
|
|
if (!sess->opts->devices || getuid() != 0) { |
if (!sess->opts->devices || getuid() != 0) { |
WARNX("skipping non-regular file %s", f->path); |
WARNX("skipping non-regular file %s", f->path); |
return 0; |
return 0; |
} else if (sess->opts->dry_run) { |
} |
|
if (sess->opts->dry_run) { |
log_file(sess, f); |
log_file(sess, f); |
return 0; |
return 0; |
} |
} |
|
|
if (!sess->opts->specials) { |
if (!sess->opts->specials) { |
WARNX("skipping non-regular file %s", f->path); |
WARNX("skipping non-regular file %s", f->path); |
return 0; |
return 0; |
} else if (sess->opts->dry_run) { |
} |
|
if (sess->opts->dry_run) { |
log_file(sess, f); |
log_file(sess, f); |
return 0; |
return 0; |
} |
} |
|
|
if (!sess->opts->specials) { |
if (!sess->opts->specials) { |
WARNX("skipping non-regular file %s", f->path); |
WARNX("skipping non-regular file %s", f->path); |
return 0; |
return 0; |
} else if (sess->opts->dry_run) { |
} |
|
if (sess->opts->dry_run) { |
log_file(sess, f); |
log_file(sess, f); |
return 0; |
return 0; |
} |
} |
|
|
if (!sess->opts->recursive) { |
if (!sess->opts->recursive) { |
WARNX("%s: ignoring directory", f->path); |
WARNX("%s: ignoring directory", f->path); |
return 0; |
return 0; |
} else if (sess->opts->dry_run) { |
} |
|
if (sess->opts->dry_run) { |
log_dir(sess, f); |
log_dir(sess, f); |
return 0; |
return 0; |
} |
} |
|
|
|
|
if (!sess->opts->recursive) |
if (!sess->opts->recursive) |
return 1; |
return 1; |
else if (sess->opts->dry_run) |
if (sess->opts->dry_run) |
return 1; |
return 1; |
|
|
if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) { |
if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) { |
ERR("%s: fstatat", f->path); |
ERR("%s: fstatat", f->path); |
return 0; |
return 0; |
} else if (!S_ISDIR(st.st_mode)) { |
} |
|
if (!S_ISDIR(st.st_mode)) { |
WARNX("%s: not a directory", f->path); |
WARNX("%s: not a directory", f->path); |
return 0; |
return 0; |
} |
} |
|
|
|
|
/* |
/* |
* Try to open the file at the current index. |
* Try to open the file at the current index. |
* If the file does not exist, returns with success. |
* If the file does not exist, returns with >0. |
* Return <0 on failure, 0 on success w/nothing to be done, >0 on |
* Return <0 on failure, 0 on success w/nothing to be done, >0 on |
* success and the file needs attention. |
* success and the file needs attention. |
*/ |
*/ |
static int |
static int |
pre_file(const struct upload *p, int *filefd, struct sess *sess) |
pre_file(const struct upload *p, int *filefd, struct stat *st, |
|
struct sess *sess) |
{ |
{ |
const struct flist *f; |
const struct flist *f; |
|
|
|
|
|
|
/* |
/* |
* For non dry-run cases, we'll write the acknowledgement later |
* For non dry-run cases, we'll write the acknowledgement later |
* in the rsync_uploader() function because we need to wait for |
* in the rsync_uploader() function. |
* the open() call to complete. |
|
* If the call to openat() fails with ENOENT, there's a |
* If the call to openat() fails with ENOENT, there's a |
* fast-path between here and the write function, so we won't do |
* fast-path between here and the write function. |
* any blocking between now and then. |
|
*/ |
*/ |
|
|
*filefd = openat(p->rootfd, f->path, |
*filefd = openat(p->rootfd, f->path, |
O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0); |
O_RDONLY | O_NOFOLLOW, 0); |
if (*filefd != -1 || errno == ENOENT) |
|
|
if (*filefd == -1 && errno != ENOENT) { |
|
ERR("%s: openat", f->path); |
|
return -1; |
|
} |
|
if (*filefd == -1) |
return 1; |
return 1; |
ERR("%s: openat", f->path); |
|
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; |
} |
} |
|
|
/* |
/* |
|
|
size_t i, pos, sz; |
size_t i, pos, sz; |
off_t offs; |
off_t offs; |
int c; |
int c; |
const struct flist *f; |
|
|
|
/* This should never get called. */ |
/* This should never get called. */ |
|
|
|
|
* have a valid buffer to write. |
* have a valid buffer to write. |
*/ |
*/ |
|
|
if (u->state == UPLOAD_WRITE_LOCAL) { |
if (u->state == UPLOAD_WRITE) { |
assert(u->buf != NULL); |
assert(u->buf != NULL); |
assert(*fileoutfd != -1); |
assert(*fileoutfd != -1); |
assert(*fileinfd == -1); |
assert(*fileinfd == -1); |
|
|
else if (S_ISLNK(u->fl[u->idx].st.mode)) |
else if (S_ISLNK(u->fl[u->idx].st.mode)) |
c = pre_link(u, sess); |
c = pre_link(u, sess); |
else if (S_ISREG(u->fl[u->idx].st.mode)) |
else if (S_ISREG(u->fl[u->idx].st.mode)) |
c = pre_file(u, fileinfd, sess); |
c = pre_file(u, fileinfd, &st, sess); |
else if (S_ISBLK(u->fl[u->idx].st.mode) || |
else if (S_ISBLK(u->fl[u->idx].st.mode) || |
S_ISCHR(u->fl[u->idx].st.mode)) |
S_ISCHR(u->fl[u->idx].st.mode)) |
c = pre_dev(u, sess); |
c = pre_dev(u, sess); |
|
|
|
|
/* Go back to the event loop, if necessary. */ |
/* Go back to the event loop, if necessary. */ |
|
|
u->state = (*fileinfd == -1) ? |
u->state = UPLOAD_WRITE; |
UPLOAD_WRITE_LOCAL : UPLOAD_READ_LOCAL; |
|
if (u->state == UPLOAD_READ_LOCAL) |
|
return 1; |
|
} |
} |
|
|
/* |
|
* If an input file is open, stat it and see if it's already up |
|
* to date, in which case close it and go to the next one. |
|
* Either way, we don't have a write channel open. |
|
*/ |
|
|
|
if (u->state == UPLOAD_READ_LOCAL) { |
|
assert(*fileinfd != -1); |
|
assert(*fileoutfd == -1); |
|
f = &u->fl[u->idx]; |
|
|
|
if (fstat(*fileinfd, &st) == -1) { |
|
ERR("%s: fstat", f->path); |
|
close(*fileinfd); |
|
*fileinfd = -1; |
|
return -1; |
|
} else if (!S_ISREG(st.st_mode)) { |
|
ERRX("%s: not regular", f->path); |
|
close(*fileinfd); |
|
*fileinfd = -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, *fileinfd, f, f->path)) { |
|
ERRX1("rsync_set_metadata"); |
|
close(*fileinfd); |
|
*fileinfd = -1; |
|
return -1; |
|
} |
|
close(*fileinfd); |
|
*fileinfd = -1; |
|
*fileoutfd = u->fdout; |
|
u->state = UPLOAD_FIND_NEXT; |
|
u->idx++; |
|
return 1; |
|
} |
|
|
|
/* Fallthrough... */ |
|
|
|
u->state = UPLOAD_WRITE_LOCAL; |
|
} |
|
|
|
/* Initialies our blocks. */ |
/* Initialies our blocks. */ |
|
|
assert(u->state == UPLOAD_WRITE_LOCAL); |
assert(u->state == UPLOAD_WRITE); |
memset(&blk, 0, sizeof(struct blkset)); |
memset(&blk, 0, sizeof(struct blkset)); |
blk.csum = u->csumlen; |
blk.csum = u->csumlen; |
|
|
|
|
return -1; |
return -1; |
} |
} |
|
|
if ((mbuf = calloc(1, blk.len)) == NULL) { |
if ((mbuf = malloc(blk.len)) == NULL) { |
ERR("calloc"); |
ERR("malloc"); |
close(*fileinfd); |
close(*fileinfd); |
*fileinfd = -1; |
*fileinfd = -1; |
return -1; |
return -1; |
|
|
i = 0; |
i = 0; |
do { |
do { |
msz = pread(*fileinfd, mbuf, blk.len, offs); |
msz = pread(*fileinfd, mbuf, blk.len, offs); |
if (msz < 0) { |
if ((size_t)msz != blk.len && (size_t)msz != blk.rem) { |
ERR("pread"); |
ERR("pread"); |
close(*fileinfd); |
close(*fileinfd); |
*fileinfd = -1; |
*fileinfd = -1; |
|
free(mbuf); |
return -1; |
return -1; |
} |
} |
if ((size_t)msz != blk.len && (size_t)msz != blk.rem) { |
|
/* short read, try again */ |
|
continue; |
|
} |
|
init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess); |
init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess); |
offs += blk.len; |
offs += blk.len; |
LOG3( |
LOG3( |
|
|
i++; |
i++; |
} while (i < blk.blksz); |
} while (i < blk.blksz); |
|
|
|
free(mbuf); |
close(*fileinfd); |
close(*fileinfd); |
*fileinfd = -1; |
*fileinfd = -1; |
LOG3("%s: mapped %jd B with %zu blocks", |
LOG3("%s: mapped %jd B with %zu blocks", |