[BACK]Return to uploader.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rsync

Annotation of src/usr.bin/rsync/uploader.c, Revision 1.9

1.9     ! florian     1: /*     $Id: uploader.c,v 1.8 2019/02/16 05:30:28 deraadt Exp $ */
1.1       benno       2: /*
                      3:  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: #include <sys/mman.h>
                     18: #include <sys/stat.h>
                     19:
                     20: #include <assert.h>
                     21: #include <errno.h>
                     22: #include <fcntl.h>
                     23: #include <inttypes.h>
                     24: #include <math.h>
                     25: #include <poll.h>
                     26: #include <stdio.h>
                     27: #include <stdlib.h>
                     28: #include <string.h>
                     29: #include <time.h>
                     30: #include <unistd.h>
                     31:
                     32: #include "extern.h"
                     33:
                     34: enum   uploadst {
                     35:        UPLOAD_FIND_NEXT = 0, /* find next to upload to sender */
                     36:        UPLOAD_WRITE_LOCAL, /* wait to write to sender */
                     37:        UPLOAD_READ_LOCAL, /* wait to read from local file */
                     38:        UPLOAD_FINISHED /* nothing more to do in phase */
                     39: };
                     40:
                     41: /*
                     42:  * Used to keep track of data flowing from the receiver to the sender.
                     43:  * This is managed by the receiver process.
                     44:  */
                     45: struct upload {
                     46:        enum uploadst       state;
                     47:        char               *buf; /* if not NULL, pending upload */
                     48:        size_t              bufsz; /* size of buf */
                     49:        size_t              bufmax; /* maximum size of buf */
                     50:        size_t              bufpos; /* position in buf */
                     51:        size_t              idx; /* current transfer index */
                     52:        mode_t              oumask; /* umask for creating files */
                     53:        int                 rootfd; /* destination directory */
                     54:        size_t              csumlen; /* checksum length */
                     55:        int                 fdout; /* write descriptor to sender */
                     56:        const struct flist *fl; /* file list */
                     57:        size_t              flsz; /* size of file list */
                     58:        int                *newdir; /* non-zero if mkdir'd */
                     59: };
                     60:
                     61: /*
                     62:  * Log a directory by emitting the file and a trailing slash, just to
                     63:  * show the operator that we're a directory.
                     64:  */
                     65: static void
                     66: log_dir(struct sess *sess, const struct flist *f)
                     67: {
                     68:        size_t   sz;
                     69:
                     70:        if (sess->opts->server)
                     71:                return;
                     72:        sz = strlen(f->path);
                     73:        assert(sz > 0);
1.7       deraadt    74:        LOG1(sess, "%s%s", f->path, ('/' == f->path[sz - 1]) ? "" : "/");
1.1       benno      75: }
                     76:
                     77: /*
                     78:  * Log a link by emitting the file and the target, just to show the
                     79:  * operator that we're a link.
                     80:  */
                     81: static void
                     82: log_link(struct sess *sess, const struct flist *f)
                     83: {
                     84:
1.3       deraadt    85:        if (!sess->opts->server)
1.1       benno      86:                LOG1(sess, "%s -> %s", f->path, f->link);
                     87: }
                     88:
                     89: /*
                     90:  * Simply log the filename.
                     91:  */
                     92: static void
                     93: log_file(struct sess *sess, const struct flist *f)
                     94: {
                     95:
1.3       deraadt    96:        if (!sess->opts->server)
1.1       benno      97:                LOG1(sess, "%s", f->path);
                     98: }
                     99:
                    100: /*
                    101:  * Prepare the overall block set's metadata.
                    102:  * We always have at least one block.
                    103:  * The block size is an important part of the algorithm.
                    104:  * I use the same heuristic as the reference rsync, but implemented in a
                    105:  * bit more of a straightforward way.
                    106:  * In general, the individual block length is the rounded square root of
                    107:  * the total file size.
                    108:  * The minimum block length is 700.
                    109:  */
                    110: static void
                    111: init_blkset(struct blkset *p, off_t sz)
                    112: {
                    113:        double   v;
                    114:
                    115:        if (sz >= (BLOCK_SIZE_MIN * BLOCK_SIZE_MIN)) {
                    116:                /* Simple rounded-up integer square root. */
                    117:
                    118:                v = sqrt(sz);
                    119:                p->len = ceil(v);
                    120:
1.2       benno     121:                /*
1.1       benno     122:                 * Always be a multiple of eight.
                    123:                 * There's no reason to do this, but rsync does.
                    124:                 */
                    125:
                    126:                if ((p->len % 8) > 0)
                    127:                        p->len += 8 - (p->len % 8);
                    128:        } else
                    129:                p->len = BLOCK_SIZE_MIN;
                    130:
                    131:        p->size = sz;
1.4       deraadt   132:        if ((p->blksz = sz / p->len) == 0)
1.1       benno     133:                p->rem = sz;
                    134:        else
                    135:                p->rem = sz % p->len;
                    136:
                    137:        /* If we have a remainder, then we need an extra block. */
                    138:
                    139:        if (p->rem)
                    140:                p->blksz++;
                    141: }
                    142:
                    143: /*
                    144:  * For each block, prepare the block's metadata.
                    145:  * We use the mapped "map" file to set our checksums.
                    146:  */
                    147: static void
                    148: init_blk(struct blk *p, const struct blkset *set, off_t offs,
                    149:        size_t idx, const void *map, const struct sess *sess)
                    150: {
                    151:
1.4       deraadt   152:        assert(map != MAP_FAILED);
1.1       benno     153:
                    154:        /* Block length inherits for all but the last. */
                    155:
                    156:        p->idx = idx;
                    157:        p->len = idx < set->blksz - 1 ? set->len : set->rem;
                    158:        p->offs = offs;
                    159:
                    160:        p->chksum_short = hash_fast(map + offs, p->len);
                    161:        hash_slow(map + offs, p->len, p->chksum_long, sess);
                    162: }
                    163:
                    164: /*
                    165:  * Return <0 on failure 0 on success.
                    166:  */
                    167: static int
                    168: pre_link(struct upload *p, struct sess *sess)
                    169: {
1.9     ! florian   170:        struct stat              st;
        !           171:        struct timespec          tv[2];
        !           172:        const struct flist      *f;
        !           173:        int                      rc, newlink = 0, updatelink = 0;
        !           174:        mode_t                   mode;
        !           175:        char                    *b;
1.1       benno     176:
                    177:        f = &p->fl[p->idx];
                    178:        assert(S_ISLNK(f->st.mode));
                    179:
1.3       deraadt   180:        if (!sess->opts->preserve_links) {
1.1       benno     181:                WARNX(sess, "%s: ignoring symlink", f->path);
                    182:                return 0;
                    183:        } else if (sess->opts->dry_run) {
                    184:                log_link(sess, f);
                    185:                return 0;
                    186:        }
                    187:
                    188:        /* See if the symlink already exists. */
                    189:
1.4       deraadt   190:        assert(p->rootfd != -1);
1.1       benno     191:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.4       deraadt   192:        if (rc != -1 && !S_ISLNK(st.st_mode)) {
1.9     ! florian   193:                if (S_ISDIR(st.st_mode)) {
        !           194:                        if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
        !           195:                                WARN(sess, "%s", f->path);
        !           196:                                return -1;
        !           197:                        }
        !           198:                }
        !           199:                rc = -1; /* overwrite object with symlink */
1.4       deraadt   200:        } else if (rc == -1 && errno != ENOENT) {
1.1       benno     201:                WARN(sess, "%s: fstatat", f->path);
                    202:                return -1;
                    203:        }
                    204:
                    205:        /*
                    206:         * If the symbolic link already exists, then make sure that it
                    207:         * points to the correct place.
                    208:         */
                    209:
1.9     ! florian   210:        if (rc != -1) {
1.1       benno     211:                b = symlinkat_read(sess, p->rootfd, f->path);
1.4       deraadt   212:                if (b == NULL) {
1.1       benno     213:                        ERRX1(sess, "%s: symlinkat_read", f->path);
                    214:                        return -1;
                    215:                }
                    216:                if (strcmp(f->link, b)) {
                    217:                        free(b);
                    218:                        b = NULL;
                    219:                        LOG3(sess, "%s: updating "
                    220:                                "symlink: %s", f->path, f->link);
1.9     ! florian   221:                        updatelink = 1;
1.2       benno     222:                }
1.1       benno     223:                free(b);
1.9     ! florian   224:                b = NULL;
        !           225:        }
        !           226:
        !           227:        if (rc == -1 || updatelink) {
        !           228:                LOG3(sess, "%s: creating "
        !           229:                        "symlink: %s", f->path, f->link);
        !           230:
        !           231:                if (mktemplate(&b, f->path, sess->opts->recursive) == -1) {
        !           232:                        ERR(sess, "asprintf");
        !           233:                        return -1;
        !           234:                }
        !           235:                if (mkstemplinkat(f->link, p->rootfd, b) == NULL) {
        !           236:                        WARN(sess, "%s: symlinkat", b);
        !           237:                        free(b);
        !           238:                        return -1;
        !           239:                }
        !           240:                newlink = 1;
1.1       benno     241:        }
                    242:
1.6       florian   243:        /*
                    244:         * Optionally preserve times/perms on the symlink.
                    245:         * FIXME: run rsync_set_metadata()?
                    246:         */
1.1       benno     247:
                    248:        if (sess->opts->preserve_times) {
1.8       deraadt   249:                struct timeval now;
                    250:
                    251:                gettimeofday(&now, NULL);
                    252:                TIMEVAL_TO_TIMESPEC(&now, &tv[0]);
1.1       benno     253:                tv[1].tv_sec = f->st.mtime;
                    254:                tv[1].tv_nsec = 0;
1.9     ! florian   255:                rc = utimensat(p->rootfd, newlink ? b : f->path, tv,
        !           256:                    AT_SYMLINK_NOFOLLOW);
1.4       deraadt   257:                if (rc == -1) {
1.9     ! florian   258:                        ERR(sess, "%s: futimes", f->path);
        !           259:                        if (newlink) {
        !           260:                                (void)unlinkat(p->rootfd, b, 0);
        !           261:                                free(b);
        !           262:                        }
1.1       benno     263:                        return -1;
                    264:                }
                    265:                LOG4(sess, "%s: updated symlink date", f->path);
                    266:        }
1.2       benno     267:
1.9     ! florian   268:        if (newlink || sess->opts->preserve_perms) {
        !           269:                if (updatelink && !sess->opts->preserve_perms)
        !           270:                        /* carry over permissions from replaced symlink */
        !           271:                        mode = st.st_mode;
        !           272:                else
        !           273:                        mode = f->st.mode;
1.1       benno     274:
1.9     ! florian   275:                rc = fchmodat(p->rootfd, newlink ? b : f->path, mode,
        !           276:                    AT_SYMLINK_NOFOLLOW);
1.4       deraadt   277:                if (rc == -1) {
1.9     ! florian   278:                        ERR(sess, "%s: fchmodat", newlink ? b : f->path);
        !           279:                        if (newlink) {
        !           280:                                (void)unlinkat(p->rootfd, b, 0);
        !           281:                                free(b);
        !           282:                        }
1.1       benno     283:                        return -1;
                    284:                }
                    285:                LOG4(sess, "%s: updated symlink mode", f->path);
1.9     ! florian   286:        }
        !           287:
        !           288:        if (newlink) {
        !           289:                if (renameat(p->rootfd, b, p->rootfd, f->path) == -1) {
        !           290:                        ERR(sess, "%s: renameat %s", b, f->path);
        !           291:                        (void)unlinkat(p->rootfd, b, 0);
        !           292:                        free(b);
        !           293:                        return -1;
        !           294:                }
        !           295:                free(b);
1.1       benno     296:        }
                    297:
                    298:        log_link(sess, f);
                    299:        return 0;
                    300: }
                    301:
                    302: /*
                    303:  * If not found, create the destination directory in prefix order.
                    304:  * Create directories using the existing umask.
                    305:  * Return <0 on failure 0 on success.
                    306:  */
                    307: static int
                    308: pre_dir(const struct upload *p, struct sess *sess)
                    309: {
                    310:        struct stat      st;
1.2       benno     311:        int              rc;
1.1       benno     312:        const struct flist *f;
                    313:
                    314:        f = &p->fl[p->idx];
                    315:        assert(S_ISDIR(f->st.mode));
                    316:
1.3       deraadt   317:        if (!sess->opts->recursive) {
1.1       benno     318:                WARNX(sess, "%s: ignoring directory", f->path);
                    319:                return 0;
                    320:        } else if (sess->opts->dry_run) {
                    321:                log_dir(sess, f);
                    322:                return 0;
                    323:        }
                    324:
1.4       deraadt   325:        assert(p->rootfd != -1);
1.1       benno     326:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.4       deraadt   327:        if (rc == -1 && errno != ENOENT) {
1.1       benno     328:                WARN(sess, "%s: fstatat", f->path);
                    329:                return -1;
1.4       deraadt   330:        } else if (rc != -1 && !S_ISDIR(st.st_mode)) {
1.1       benno     331:                WARNX(sess, "%s: not a directory", f->path);
                    332:                return -1;
1.4       deraadt   333:        } else if (rc != -1) {
1.2       benno     334:                /*
1.1       benno     335:                 * FIXME: we should fchmod the permissions here as well,
                    336:                 * as we may locally have shut down writing into the
                    337:                 * directory and that doesn't work.
                    338:                 */
                    339:                LOG3(sess, "%s: updating directory", f->path);
                    340:                return 0;
                    341:        }
                    342:
                    343:        /*
                    344:         * We want to make the directory with default permissions (using
                    345:         * our old umask, which we've since unset), then adjust
                    346:         * permissions (assuming preserve_perms or new) afterward in
                    347:         * case it's u-w or something.
                    348:         */
                    349:
                    350:        LOG3(sess, "%s: creating directory", f->path);
1.4       deraadt   351:        if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) {
1.1       benno     352:                WARN(sess, "%s: mkdirat", f->path);
                    353:                return -1;
                    354:        }
                    355:
                    356:        p->newdir[p->idx] = 1;
                    357:        log_dir(sess, f);
                    358:        return 0;
                    359: }
                    360:
                    361: /*
                    362:  * Process the directory time and mode for "idx" in the file list.
                    363:  * Returns zero on failure, non-zero on success.
                    364:  */
                    365: static int
                    366: post_dir(struct sess *sess, const struct upload *u, size_t idx)
                    367: {
                    368:        struct timespec  tv[2];
                    369:        int              rc;
                    370:        struct stat      st;
                    371:        const struct flist *f;
                    372:
                    373:        f = &u->fl[idx];
                    374:        assert(S_ISDIR(f->st.mode));
                    375:
                    376:        /* We already warned about the directory in pre_process_dir(). */
                    377:
1.3       deraadt   378:        if (!sess->opts->recursive)
1.1       benno     379:                return 1;
                    380:        else if (sess->opts->dry_run)
                    381:                return 1;
                    382:
1.4       deraadt   383:        if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
1.1       benno     384:                ERR(sess, "%s: fstatat", f->path);
                    385:                return 0;
1.3       deraadt   386:        } else if (!S_ISDIR(st.st_mode)) {
1.1       benno     387:                WARNX(sess, "%s: not a directory", f->path);
                    388:                return 0;
                    389:        }
                    390:
1.2       benno     391:        /*
1.1       benno     392:         * Update the modification time if we're a new directory *or* if
                    393:         * we're preserving times and the time has changed.
1.6       florian   394:         * FIXME: run rsync_set_metadata()?
1.1       benno     395:         */
                    396:
1.2       benno     397:        if (u->newdir[idx] ||
                    398:            (sess->opts->preserve_times &&
1.1       benno     399:             st.st_mtime != f->st.mtime)) {
                    400:                tv[0].tv_sec = time(NULL);
                    401:                tv[0].tv_nsec = 0;
                    402:                tv[1].tv_sec = f->st.mtime;
                    403:                tv[1].tv_nsec = 0;
                    404:                rc = utimensat(u->rootfd, f->path, tv, 0);
1.4       deraadt   405:                if (rc == -1) {
1.1       benno     406:                        ERR(sess, "%s: utimensat", f->path);
                    407:                        return 0;
                    408:                }
                    409:                LOG4(sess, "%s: updated date", f->path);
                    410:        }
                    411:
                    412:        /*
                    413:         * Update the mode if we're a new directory *or* if we're
                    414:         * preserving modes and it has changed.
                    415:         */
                    416:
1.2       benno     417:        if (u->newdir[idx] ||
1.1       benno     418:            (sess->opts->preserve_perms &&
                    419:             st.st_mode != f->st.mode)) {
                    420:                rc = fchmodat(u->rootfd, f->path, f->st.mode, 0);
1.4       deraadt   421:                if (rc == -1) {
1.1       benno     422:                        ERR(sess, "%s: fchmodat", f->path);
                    423:                        return 0;
                    424:                }
                    425:                LOG4(sess, "%s: updated mode", f->path);
                    426:        }
                    427:
                    428:        return 1;
                    429: }
                    430:
                    431: /*
                    432:  * Try to open the file at the current index.
                    433:  * If the file does not exist, returns with success.
                    434:  * Return <0 on failure, 0 on success w/nothing to be done, >0 on
                    435:  * success and the file needs attention.
                    436:  */
                    437: static int
                    438: pre_file(const struct upload *p, int *filefd, struct sess *sess)
                    439: {
                    440:        const struct flist *f;
                    441:
                    442:        f = &p->fl[p->idx];
                    443:        assert(S_ISREG(f->st.mode));
                    444:
                    445:        if (sess->opts->dry_run) {
                    446:                log_file(sess, f);
1.3       deraadt   447:                if (!io_write_int(sess, p->fdout, p->idx)) {
1.1       benno     448:                        ERRX1(sess, "io_write_int");
                    449:                        return -1;
                    450:                }
                    451:                return 0;
                    452:        }
                    453:
                    454:        /*
                    455:         * For non dry-run cases, we'll write the acknowledgement later
                    456:         * in the rsync_uploader() function because we need to wait for
                    457:         * the open() call to complete.
                    458:         * If the call to openat() fails with ENOENT, there's a
                    459:         * fast-path between here and the write function, so we won't do
                    460:         * any blocking between now and then.
                    461:         */
                    462:
                    463:        *filefd = openat(p->rootfd, f->path,
                    464:                O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0);
1.4       deraadt   465:        if (*filefd != -1 || errno == ENOENT)
1.1       benno     466:                return 1;
                    467:        ERR(sess, "%s: openat", f->path);
                    468:        return -1;
                    469: }
                    470:
                    471: /*
                    472:  * Allocate an uploader object in the correct state to start.
                    473:  * Returns NULL on failure or the pointer otherwise.
                    474:  * On success, upload_free() must be called with the allocated pointer.
                    475:  */
                    476: struct upload *
1.2       benno     477: upload_alloc(struct sess *sess, int rootfd, int fdout,
1.1       benno     478:        size_t clen, const struct flist *fl, size_t flsz, mode_t msk)
                    479: {
                    480:        struct upload   *p;
                    481:
1.4       deraadt   482:        if ((p = calloc(1, sizeof(struct upload))) == NULL) {
1.1       benno     483:                ERR(sess, "calloc");
                    484:                return NULL;
                    485:        }
                    486:
                    487:        p->state = UPLOAD_FIND_NEXT;
                    488:        p->oumask = msk;
                    489:        p->rootfd = rootfd;
                    490:        p->csumlen = clen;
                    491:        p->fdout = fdout;
                    492:        p->fl = fl;
                    493:        p->flsz = flsz;
                    494:        p->newdir = calloc(flsz, sizeof(int));
1.4       deraadt   495:        if (p->newdir == NULL) {
1.1       benno     496:                ERR(sess, "calloc");
                    497:                free(p);
                    498:                return NULL;
                    499:        }
                    500:        return p;
                    501: }
                    502:
                    503: /*
                    504:  * Perform all cleanups and free.
                    505:  * Passing a NULL to this function is ok.
                    506:  */
                    507: void
                    508: upload_free(struct upload *p)
                    509: {
                    510:
1.4       deraadt   511:        if (p == NULL)
1.1       benno     512:                return;
                    513:        free(p->newdir);
                    514:        free(p->buf);
                    515:        free(p);
                    516: }
                    517:
                    518: /*
                    519:  * Iterates through all available files and conditionally gets the file
                    520:  * ready for processing to check whether it's up to date.
                    521:  * If not up to date or empty, sends file information to the sender.
                    522:  * If returns 0, we've processed all files there are to process.
                    523:  * If returns >0, we're waiting for POLLIN or POLLOUT data.
                    524:  * Otherwise returns <0, which is an error.
                    525:  */
                    526: int
1.2       benno     527: rsync_uploader(struct upload *u, int *fileinfd,
1.1       benno     528:        struct sess *sess, int *fileoutfd)
                    529: {
1.5       florian   530:        struct blkset       blk;
                    531:        struct stat         st;
                    532:        void               *map, *bufp;
                    533:        size_t              i, mapsz, pos, sz;
                    534:        off_t               offs;
                    535:        int                 c;
                    536:        const struct flist *f;
1.1       benno     537:
                    538:        /* This should never get called. */
                    539:
1.4       deraadt   540:        assert(u->state != UPLOAD_FINISHED);
1.1       benno     541:
                    542:        /*
                    543:         * If we have an upload in progress, then keep writing until the
                    544:         * buffer has been fully written.
                    545:         * We must only have the output file descriptor working and also
                    546:         * have a valid buffer to write.
                    547:         */
                    548:
1.4       deraadt   549:        if (u->state == UPLOAD_WRITE_LOCAL) {
1.1       benno     550:                assert(NULL != u->buf);
1.4       deraadt   551:                assert(*fileoutfd != -1);
                    552:                assert(*fileinfd == -1);
1.1       benno     553:
                    554:                /*
                    555:                 * Unfortunately, we need to chunk these: if we're
                    556:                 * the server side of things, then we're multiplexing
                    557:                 * output and need to wrap this in chunks.
                    558:                 * This is a major deficiency of rsync.
                    559:                 * FIXME: add a "fast-path" mode that simply dumps out
                    560:                 * the buffer non-blocking if we're not mplexing.
                    561:                 */
                    562:
                    563:                if (u->bufpos < u->bufsz) {
                    564:                        sz = MAX_CHUNK < (u->bufsz - u->bufpos) ?
                    565:                                MAX_CHUNK : (u->bufsz - u->bufpos);
1.2       benno     566:                        c = io_write_buf(sess, u->fdout,
1.1       benno     567:                                u->buf + u->bufpos, sz);
1.4       deraadt   568:                        if (c == 0) {
1.1       benno     569:                                ERRX1(sess, "io_write_nonblocking");
                    570:                                return -1;
                    571:                        }
                    572:                        u->bufpos += sz;
                    573:                        if (u->bufpos < u->bufsz)
                    574:                                return 1;
                    575:                }
                    576:
1.2       benno     577:                /*
1.1       benno     578:                 * Let the UPLOAD_FIND_NEXT state handle things if we
                    579:                 * finish, as we'll need to write a POLLOUT message and
                    580:                 * not have a writable descriptor yet.
                    581:                 */
                    582:
                    583:                u->state = UPLOAD_FIND_NEXT;
                    584:                u->idx++;
                    585:                return 1;
                    586:        }
                    587:
                    588:        /*
                    589:         * If we invoke the uploader without a file currently open, then
                    590:         * we iterate through til the next available regular file and
                    591:         * start the opening process.
                    592:         * This means we must have the output file descriptor working.
                    593:         */
                    594:
1.4       deraadt   595:        if (u->state == UPLOAD_FIND_NEXT) {
                    596:                assert(*fileinfd == -1);
                    597:                assert(*fileoutfd != -1);
1.1       benno     598:
                    599:                for ( ; u->idx < u->flsz; u->idx++) {
                    600:                        if (S_ISDIR(u->fl[u->idx].st.mode))
                    601:                                c = pre_dir(u, sess);
                    602:                        else if (S_ISLNK(u->fl[u->idx].st.mode))
                    603:                                c = pre_link(u, sess);
                    604:                        else if (S_ISREG(u->fl[u->idx].st.mode))
                    605:                                c = pre_file(u, fileinfd, sess);
                    606:                        else
                    607:                                c = 0;
                    608:
                    609:                        if (c < 0)
                    610:                                return -1;
                    611:                        else if (c > 0)
                    612:                                break;
                    613:                }
                    614:
1.2       benno     615:                /*
1.1       benno     616:                 * Whether we've finished writing files or not, we
                    617:                 * disable polling on the output channel.
                    618:                 */
                    619:
                    620:                *fileoutfd = -1;
                    621:                if (u->idx == u->flsz) {
1.4       deraadt   622:                        assert(*fileinfd == -1);
1.3       deraadt   623:                        if (!io_write_int(sess, u->fdout, -1)) {
1.1       benno     624:                                ERRX1(sess, "io_write_int");
                    625:                                return -1;
                    626:                        }
                    627:                        u->state = UPLOAD_FINISHED;
                    628:                        LOG4(sess, "uploader: finished");
                    629:                        return 0;
                    630:                }
                    631:
                    632:                /* Go back to the event loop, if necessary. */
                    633:
                    634:                u->state = -1 == *fileinfd ?
                    635:                        UPLOAD_WRITE_LOCAL : UPLOAD_READ_LOCAL;
1.4       deraadt   636:                if (u->state == UPLOAD_READ_LOCAL)
1.1       benno     637:                        return 1;
                    638:        }
                    639:
1.2       benno     640:        /*
1.1       benno     641:         * If an input file is open, stat it and see if it's already up
                    642:         * to date, in which case close it and go to the next one.
                    643:         * Either way, we don't have a write channel open.
                    644:         */
                    645:
1.4       deraadt   646:        if (u->state == UPLOAD_READ_LOCAL) {
                    647:                assert(*fileinfd != -1);
                    648:                assert(*fileoutfd == -1);
1.5       florian   649:                f = &u->fl[u->idx];
1.1       benno     650:
1.4       deraadt   651:                if (fstat(*fileinfd, &st) == -1) {
1.5       florian   652:                        ERR(sess, "%s: fstat", f->path);
1.1       benno     653:                        close(*fileinfd);
                    654:                        *fileinfd = -1;
                    655:                        return -1;
1.3       deraadt   656:                } else if (!S_ISREG(st.st_mode)) {
1.5       florian   657:                        ERRX(sess, "%s: not regular", f->path);
1.1       benno     658:                        close(*fileinfd);
                    659:                        *fileinfd = -1;
                    660:                        return -1;
                    661:                }
                    662:
1.5       florian   663:                if (st.st_size == f->st.size &&
                    664:                    st.st_mtime == f->st.mtime) {
                    665:                        LOG3(sess, "%s: skipping: up to date", f->path);
                    666: #if 0
                    667:                        /* Not yet: investigate behaviour. */
                    668:                        if (!rsync_set_metadata
                    669:                            (sess, 0, *fileinfd, f, f->path)) {
                    670:                                ERRX1(sess, "rsync_set_metadata");
                    671:                                close(*fileinfd);
                    672:                                *fileinfd = -1;
                    673:                                return -1;
                    674:                        }
                    675: #endif
1.1       benno     676:                        close(*fileinfd);
                    677:                        *fileinfd = -1;
                    678:                        *fileoutfd = u->fdout;
                    679:                        u->state = UPLOAD_FIND_NEXT;
                    680:                        u->idx++;
                    681:                        return 1;
                    682:                }
                    683:
                    684:                /* Fallthrough... */
                    685:
                    686:                u->state = UPLOAD_WRITE_LOCAL;
                    687:        }
                    688:
                    689:        /* Initialies our blocks. */
                    690:
1.4       deraadt   691:        assert(u->state == UPLOAD_WRITE_LOCAL);
1.1       benno     692:        memset(&blk, 0, sizeof(struct blkset));
                    693:        blk.csum = u->csumlen;
                    694:
1.4       deraadt   695:        if (*fileinfd != -1 && st.st_size > 0) {
1.1       benno     696:                mapsz = st.st_size;
1.7       deraadt   697:                map = mmap(NULL, mapsz, PROT_READ, MAP_SHARED, *fileinfd, 0);
1.4       deraadt   698:                if (map == MAP_FAILED) {
1.1       benno     699:                        WARN(sess, "%s: mmap", u->fl[u->idx].path);
                    700:                        close(*fileinfd);
                    701:                        *fileinfd = -1;
                    702:                        return -1;
                    703:                }
                    704:
                    705:                init_blkset(&blk, st.st_size);
                    706:                assert(blk.blksz);
                    707:
                    708:                blk.blks = calloc(blk.blksz, sizeof(struct blk));
1.4       deraadt   709:                if (blk.blks == NULL) {
1.1       benno     710:                        ERR(sess, "calloc");
                    711:                        munmap(map, mapsz);
                    712:                        close(*fileinfd);
                    713:                        *fileinfd = -1;
                    714:                        return -1;
                    715:                }
                    716:
                    717:                offs = 0;
                    718:                for (i = 0; i < blk.blksz; i++) {
1.2       benno     719:                        init_blk(&blk.blks[i],
1.1       benno     720:                                &blk, offs, i, map, sess);
                    721:                        offs += blk.len;
                    722:                }
                    723:
                    724:                munmap(map, mapsz);
                    725:                close(*fileinfd);
                    726:                *fileinfd = -1;
                    727:                LOG3(sess, "%s: mapped %jd B with %zu blocks",
1.2       benno     728:                        u->fl[u->idx].path, (intmax_t)blk.size,
1.1       benno     729:                        blk.blksz);
                    730:        } else {
1.4       deraadt   731:                if (*fileinfd != -1) {
1.1       benno     732:                        close(*fileinfd);
                    733:                        *fileinfd = -1;
                    734:                }
                    735:                blk.len = MAX_CHUNK; /* Doesn't matter. */
                    736:                LOG3(sess, "%s: not mapped", u->fl[u->idx].path);
                    737:        }
                    738:
1.4       deraadt   739:        assert(*fileinfd == -1);
1.1       benno     740:
                    741:        /* Make sure the block metadata buffer is big enough. */
                    742:
1.2       benno     743:        u->bufsz =
1.1       benno     744:             sizeof(int32_t) + /* identifier */
                    745:             sizeof(int32_t) + /* block count */
                    746:             sizeof(int32_t) + /* block length */
                    747:             sizeof(int32_t) + /* checksum length */
                    748:             sizeof(int32_t) + /* block remainder */
1.2       benno     749:             blk.blksz *
1.1       benno     750:             (sizeof(int32_t) + /* short checksum */
                    751:              blk.csum); /* long checksum */
                    752:
                    753:        if (u->bufsz > u->bufmax) {
1.4       deraadt   754:                if ((bufp = realloc(u->buf, u->bufsz)) == NULL) {
1.1       benno     755:                        ERR(sess, "realloc");
                    756:                        return -1;
                    757:                }
                    758:                u->buf = bufp;
                    759:                u->bufmax = u->bufsz;
                    760:        }
                    761:
                    762:        u->bufpos = pos = 0;
                    763:        io_buffer_int(sess, u->buf, &pos, u->bufsz, u->idx);
                    764:        io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.blksz);
                    765:        io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.len);
                    766:        io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.csum);
                    767:        io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.rem);
                    768:        for (i = 0; i < blk.blksz; i++) {
1.2       benno     769:                io_buffer_int(sess, u->buf, &pos, u->bufsz,
1.1       benno     770:                        blk.blks[i].chksum_short);
1.2       benno     771:                io_buffer_buf(sess, u->buf, &pos, u->bufsz,
1.1       benno     772:                        blk.blks[i].chksum_long, blk.csum);
                    773:        }
                    774:        assert(pos == u->bufsz);
                    775:
                    776:        /* Reenable the output poller and clean up. */
                    777:
                    778:        *fileoutfd = u->fdout;
                    779:        free(blk.blks);
                    780:        return 1;
                    781: }
                    782:
                    783: /*
                    784:  * Fix up the directory permissions and times post-order.
                    785:  * We can't fix up directory permissions in place because the server may
                    786:  * want us to have overly-tight permissions---say, those that don't
                    787:  * allow writing into the directory.
                    788:  * We also need to do our directory times post-order because making
                    789:  * files within the directory will change modification times.
                    790:  * Returns zero on failure, non-zero on success.
                    791:  */
                    792: int
                    793: rsync_uploader_tail(struct upload *u, struct sess *sess)
                    794: {
                    795:        size_t   i;
                    796:
                    797:
1.3       deraadt   798:        if (!sess->opts->preserve_times &&
                    799:             !sess->opts->preserve_perms)
1.1       benno     800:                return 1;
                    801:
                    802:        LOG2(sess, "fixing up directory times and permissions");
                    803:
                    804:        for (i = 0; i < u->flsz; i++)
                    805:                if (S_ISDIR(u->fl[i].st.mode))
1.3       deraadt   806:                        if (!post_dir(sess, u, i))
1.1       benno     807:                                return 0;
                    808:
                    809:        return 1;
                    810: }