[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.29

1.29    ! claudio     1: /*     $OpenBSD: uploader.c,v 1.28 2021/05/17 12:15:48 claudio Exp $ */
1.1       benno       2: /*
                      3:  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
1.12      florian     4:  * Copyright (c) 2019 Florian Obser <florian@openbsd.org>
1.1       benno       5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18: #include <sys/mman.h>
                     19: #include <sys/stat.h>
                     20:
                     21: #include <assert.h>
                     22: #include <errno.h>
                     23: #include <fcntl.h>
                     24: #include <inttypes.h>
                     25: #include <math.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 */
1.25      claudio    36:        UPLOAD_WRITE, /* wait to write to sender */
1.1       benno      37:        UPLOAD_FINISHED /* nothing more to do in phase */
                     38: };
                     39:
                     40: /*
                     41:  * Used to keep track of data flowing from the receiver to the sender.
                     42:  * This is managed by the receiver process.
                     43:  */
                     44: struct upload {
                     45:        enum uploadst       state;
                     46:        char               *buf; /* if not NULL, pending upload */
                     47:        size_t              bufsz; /* size of buf */
                     48:        size_t              bufmax; /* maximum size of buf */
                     49:        size_t              bufpos; /* position in buf */
                     50:        size_t              idx; /* current transfer index */
                     51:        mode_t              oumask; /* umask for creating files */
1.11      florian    52:        char               *root; /* destination directory path */
1.1       benno      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.21      benno      74:        LOG1("%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
1.26      claudio    82: log_symlink(struct sess *sess, const struct flist *f)
1.1       benno      83: {
                     84:
1.3       deraadt    85:        if (!sess->opts->server)
1.21      benno      86:                LOG1("%s -> %s", f->path, f->link);
1.1       benno      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.21      benno      97:                LOG1("%s", f->path);
1.1       benno      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.24      claudio   152:        p->idx = idx;
1.1       benno     153:        /* Block length inherits for all but the last. */
                    154:        p->len = idx < set->blksz - 1 ? set->len : set->rem;
                    155:        p->offs = offs;
                    156:
1.23      benno     157:        p->chksum_short = hash_fast(map, p->len);
                    158:        hash_slow(map, p->len, p->chksum_long, sess);
1.1       benno     159: }
                    160:
                    161: /*
1.17      benno     162:  * Handle a symbolic link.
                    163:  * If we encounter directories existing in the symbolic link's place,
                    164:  * then try to unlink the directory.
                    165:  * Otherwise, simply overwrite with the symbolic link by renaming.
1.1       benno     166:  * Return <0 on failure 0 on success.
                    167:  */
                    168: static int
                    169: pre_link(struct upload *p, struct sess *sess)
                    170: {
1.9       florian   171:        struct stat              st;
                    172:        const struct flist      *f;
                    173:        int                      rc, newlink = 0, updatelink = 0;
1.11      florian   174:        char                    *b, *temp = NULL;
1.1       benno     175:
                    176:        f = &p->fl[p->idx];
                    177:        assert(S_ISLNK(f->st.mode));
                    178:
1.3       deraadt   179:        if (!sess->opts->preserve_links) {
1.21      benno     180:                WARNX("%s: ignoring symlink", f->path);
1.1       benno     181:                return 0;
1.25      claudio   182:        }
                    183:        if (sess->opts->dry_run) {
1.26      claudio   184:                log_symlink(sess, f);
1.1       benno     185:                return 0;
                    186:        }
                    187:
1.17      benno     188:        /*
                    189:         * See if the symlink already exists.
                    190:         * If it's a directory, then try to unlink the directory prior
                    191:         * to overwriting with a symbolic link.
                    192:         * If it's a non-directory, we just overwrite it.
                    193:         */
1.1       benno     194:
1.4       deraadt   195:        assert(p->rootfd != -1);
1.1       benno     196:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.28      claudio   197:
                    198:        if (rc == -1 && errno != ENOENT) {
                    199:                ERR("%s: fstatat", f->path);
                    200:                return -1;
                    201:        }
1.4       deraadt   202:        if (rc != -1 && !S_ISLNK(st.st_mode)) {
1.17      benno     203:                if (S_ISDIR(st.st_mode) &&
                    204:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
1.21      benno     205:                        ERR("%s: unlinkat", f->path);
1.17      benno     206:                        return -1;
1.9       florian   207:                }
1.17      benno     208:                rc = -1;
1.1       benno     209:        }
                    210:
                    211:        /*
                    212:         * If the symbolic link already exists, then make sure that it
                    213:         * points to the correct place.
                    214:         */
                    215:
1.9       florian   216:        if (rc != -1) {
1.22      benno     217:                b = symlinkat_read(p->rootfd, f->path);
1.4       deraadt   218:                if (b == NULL) {
1.21      benno     219:                        ERRX1("symlinkat_read");
1.1       benno     220:                        return -1;
                    221:                }
                    222:                if (strcmp(f->link, b)) {
                    223:                        free(b);
                    224:                        b = NULL;
1.21      benno     225:                        LOG3("%s: updating symlink: %s", f->path, f->link);
1.9       florian   226:                        updatelink = 1;
1.2       benno     227:                }
1.1       benno     228:                free(b);
1.9       florian   229:                b = NULL;
                    230:        }
                    231:
1.17      benno     232:        /*
                    233:         * Create the temporary file as a symbolic link, then rename the
                    234:         * temporary file as the real one, overwriting anything there.
                    235:         */
                    236:
1.9       florian   237:        if (rc == -1 || updatelink) {
1.21      benno     238:                LOG3("%s: creating symlink: %s", f->path, f->link);
1.22      benno     239:                if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
1.21      benno     240:                        ERRX1("mktemplate");
1.9       florian   241:                        return -1;
                    242:                }
1.11      florian   243:                if (mkstemplinkat(f->link, p->rootfd, temp) == NULL) {
1.21      benno     244:                        ERR("mkstemplinkat");
1.11      florian   245:                        free(temp);
1.9       florian   246:                        return -1;
                    247:                }
                    248:                newlink = 1;
1.1       benno     249:        }
                    250:
1.17      benno     251:        rsync_set_metadata_at(sess, newlink,
                    252:                p->rootfd, f, newlink ? temp : f->path);
1.11      florian   253:
                    254:        if (newlink) {
                    255:                if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
1.21      benno     256:                        ERR("%s: renameat %s", temp, f->path);
1.11      florian   257:                        (void)unlinkat(p->rootfd, temp, 0);
                    258:                        free(temp);
                    259:                        return -1;
                    260:                }
                    261:                free(temp);
                    262:        }
                    263:
1.26      claudio   264:        log_symlink(sess, f);
1.11      florian   265:        return 0;
                    266: }
                    267:
                    268: /*
1.17      benno     269:  * See pre_link(), but for devices.
                    270:  * FIXME: this is very similar to the other pre_xxx() functions.
1.11      florian   271:  * Return <0 on failure 0 on success.
                    272:  */
                    273: static int
                    274: pre_dev(struct upload *p, struct sess *sess)
                    275: {
                    276:        struct stat              st;
                    277:        const struct flist      *f;
                    278:        int                      rc, newdev = 0, updatedev = 0;
                    279:        char                    *temp = NULL;
                    280:
                    281:        f = &p->fl[p->idx];
                    282:        assert(S_ISBLK(f->st.mode) || S_ISCHR(f->st.mode));
                    283:
                    284:        if (!sess->opts->devices || getuid() != 0) {
1.21      benno     285:                WARNX("skipping non-regular file %s", f->path);
1.11      florian   286:                return 0;
1.25      claudio   287:        }
                    288:        if (sess->opts->dry_run) {
1.11      florian   289:                log_file(sess, f);
                    290:                return 0;
                    291:        }
                    292:
1.17      benno     293:        /*
                    294:         * See if the dev already exists.
                    295:         * If a non-device exists in its place, we'll replace that.
                    296:         * If it replaces a directory, remove the directory first.
                    297:         */
                    298:
1.16      benno     299:        assert(p->rootfd != -1);
1.11      florian   300:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
                    301:
1.28      claudio   302:        if (rc == -1 && errno != ENOENT) {
                    303:                ERR("%s: fstatat", f->path);
                    304:                return -1;
                    305:        }
1.11      florian   306:        if (rc != -1 && !(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) {
1.17      benno     307:                if (S_ISDIR(st.st_mode) &&
                    308:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
1.21      benno     309:                        ERR("%s: unlinkat", f->path);
1.17      benno     310:                        return -1;
1.11      florian   311:                }
1.17      benno     312:                rc = -1;
1.11      florian   313:        }
                    314:
1.17      benno     315:        /* Make sure existing device is of the correct type. */
1.1       benno     316:
1.11      florian   317:        if (rc != -1) {
                    318:                if ((f->st.mode & (S_IFCHR|S_IFBLK)) !=
1.17      benno     319:                    (st.st_mode & (S_IFCHR|S_IFBLK)) ||
                    320:                    f->st.rdev != st.st_rdev) {
1.21      benno     321:                        LOG3("%s: updating device", f->path);
1.11      florian   322:                        updatedev = 1;
                    323:                }
                    324:        }
                    325:
                    326:        if (rc == -1 || updatedev) {
                    327:                newdev = 1;
1.22      benno     328:                if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
1.21      benno     329:                        ERRX1("mktemplate");
1.11      florian   330:                        return -1;
                    331:                }
1.17      benno     332:                if (mkstempnodat(p->rootfd, temp,
                    333:                    f->st.mode & (S_IFCHR|S_IFBLK), f->st.rdev) == NULL) {
1.21      benno     334:                        ERR("mkstempnodat");
1.11      florian   335:                        free(temp);
                    336:                        return -1;
                    337:                }
                    338:        }
                    339:
1.17      benno     340:        rsync_set_metadata_at(sess, newdev,
1.22      benno     341:            p->rootfd, f, newdev ? temp : f->path);
1.11      florian   342:
                    343:        if (newdev) {
                    344:                if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
1.21      benno     345:                        ERR("%s: renameat %s", temp, f->path);
1.11      florian   346:                        (void)unlinkat(p->rootfd, temp, 0);
                    347:                        free(temp);
                    348:                        return -1;
                    349:                }
                    350:                free(temp);
                    351:        }
1.17      benno     352:
1.11      florian   353:        log_file(sess, f);
                    354:        return 0;
                    355: }
                    356:
                    357: /*
1.17      benno     358:  * See pre_link(), but for FIFOs.
                    359:  * FIXME: this is very similar to the other pre_xxx() functions.
1.11      florian   360:  * Return <0 on failure 0 on success.
                    361:  */
                    362: static int
                    363: pre_fifo(struct upload *p, struct sess *sess)
                    364: {
                    365:        struct stat              st;
                    366:        const struct flist      *f;
                    367:        int                      rc, newfifo = 0;
                    368:        char                    *temp = NULL;
                    369:
                    370:        f = &p->fl[p->idx];
                    371:        assert(S_ISFIFO(f->st.mode));
                    372:
                    373:        if (!sess->opts->specials) {
1.21      benno     374:                WARNX("skipping non-regular file %s", f->path);
1.11      florian   375:                return 0;
1.25      claudio   376:        }
                    377:        if (sess->opts->dry_run) {
1.11      florian   378:                log_file(sess, f);
                    379:                return 0;
                    380:        }
                    381:
1.17      benno     382:        /*
                    383:         * See if the fifo already exists.
                    384:         * If it exists as a non-FIFO, unlink it (if a directory) then
                    385:         * mark it from replacement.
                    386:         */
                    387:
1.16      benno     388:        assert(p->rootfd != -1);
1.11      florian   389:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.8       deraadt   390:
1.28      claudio   391:        if (rc == -1 && errno != ENOENT) {
                    392:                ERR("%s: fstatat", f->path);
                    393:                return -1;
                    394:        }
1.11      florian   395:        if (rc != -1 && !S_ISFIFO(st.st_mode)) {
1.17      benno     396:                if (S_ISDIR(st.st_mode) &&
                    397:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
1.21      benno     398:                        ERR("%s: unlinkat", f->path);
1.17      benno     399:                        return -1;
1.11      florian   400:                }
1.17      benno     401:                rc = -1;
1.11      florian   402:        }
                    403:
                    404:        if (rc == -1) {
                    405:                newfifo = 1;
1.22      benno     406:                if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
1.21      benno     407:                        ERRX1("mktemplate");
1.11      florian   408:                        return -1;
                    409:                }
                    410:                if (mkstempfifoat(p->rootfd, temp) == NULL) {
1.21      benno     411:                        ERR("mkstempfifoat");
1.11      florian   412:                        free(temp);
1.1       benno     413:                        return -1;
                    414:                }
                    415:        }
1.2       benno     416:
1.17      benno     417:        rsync_set_metadata_at(sess, newfifo,
                    418:                p->rootfd, f, newfifo ? temp : f->path);
1.11      florian   419:
                    420:        if (newfifo) {
                    421:                if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
1.21      benno     422:                        ERR("%s: renameat %s", temp, f->path);
1.11      florian   423:                        (void)unlinkat(p->rootfd, temp, 0);
                    424:                        free(temp);
                    425:                        return -1;
                    426:                }
                    427:                free(temp);
                    428:        }
1.17      benno     429:
1.11      florian   430:        log_file(sess, f);
                    431:        return 0;
                    432: }
1.1       benno     433:
1.11      florian   434: /*
1.17      benno     435:  * See pre_link(), but for socket files.
                    436:  * FIXME: this is very similar to the other pre_xxx() functions.
1.11      florian   437:  * Return <0 on failure 0 on success.
                    438:  */
                    439: static int
                    440: pre_sock(struct upload *p, struct sess *sess)
                    441: {
                    442:        struct stat              st;
                    443:        const struct flist      *f;
                    444:        int                      rc, newsock = 0;
                    445:        char                    *temp = NULL;
                    446:
                    447:        f = &p->fl[p->idx];
                    448:        assert(S_ISSOCK(f->st.mode));
                    449:
                    450:        if (!sess->opts->specials) {
1.21      benno     451:                WARNX("skipping non-regular file %s", f->path);
1.11      florian   452:                return 0;
1.25      claudio   453:        }
                    454:        if (sess->opts->dry_run) {
1.11      florian   455:                log_file(sess, f);
                    456:                return 0;
                    457:        }
                    458:
1.17      benno     459:        /*
                    460:         * See if the fifo already exists.
                    461:         * If it exists as a non-FIFO, unlink it (if a directory) then
                    462:         * mark it from replacement.
                    463:         */
                    464:
1.18      deraadt   465:        assert(p->rootfd != -1);
1.11      florian   466:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
                    467:
1.28      claudio   468:        if (rc == -1 && errno != ENOENT) {
                    469:                ERR("%s: fstatat", f->path);
                    470:                return -1;
                    471:        }
1.11      florian   472:        if (rc != -1 && !S_ISSOCK(st.st_mode)) {
1.17      benno     473:                if (S_ISDIR(st.st_mode) &&
                    474:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
1.21      benno     475:                        ERR("%s: unlinkat", f->path);
1.17      benno     476:                        return -1;
1.11      florian   477:                }
1.17      benno     478:                rc = -1;
1.11      florian   479:        }
                    480:
                    481:        if (rc == -1) {
                    482:                newsock = 1;
1.22      benno     483:                if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
1.21      benno     484:                        ERRX1("mktemplate");
1.11      florian   485:                        return -1;
                    486:                }
                    487:                if (mkstempsock(p->root, temp) == NULL) {
1.21      benno     488:                        ERR("mkstempsock");
1.11      florian   489:                        free(temp);
1.1       benno     490:                        return -1;
                    491:                }
1.9       florian   492:        }
                    493:
1.17      benno     494:        rsync_set_metadata_at(sess, newsock,
                    495:                p->rootfd, f, newsock ? temp : f->path);
1.11      florian   496:
                    497:        if (newsock) {
                    498:                if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
1.21      benno     499:                        ERR("%s: renameat %s", temp, f->path);
1.11      florian   500:                        (void)unlinkat(p->rootfd, temp, 0);
                    501:                        free(temp);
1.9       florian   502:                        return -1;
                    503:                }
1.11      florian   504:                free(temp);
1.1       benno     505:        }
1.17      benno     506:
1.11      florian   507:        log_file(sess, f);
1.1       benno     508:        return 0;
                    509: }
                    510:
                    511: /*
                    512:  * If not found, create the destination directory in prefix order.
                    513:  * Create directories using the existing umask.
                    514:  * Return <0 on failure 0 on success.
                    515:  */
                    516: static int
                    517: pre_dir(const struct upload *p, struct sess *sess)
                    518: {
                    519:        struct stat      st;
1.2       benno     520:        int              rc;
1.1       benno     521:        const struct flist *f;
                    522:
                    523:        f = &p->fl[p->idx];
                    524:        assert(S_ISDIR(f->st.mode));
                    525:
1.3       deraadt   526:        if (!sess->opts->recursive) {
1.21      benno     527:                WARNX("%s: ignoring directory", f->path);
1.1       benno     528:                return 0;
1.25      claudio   529:        }
                    530:        if (sess->opts->dry_run) {
1.1       benno     531:                log_dir(sess, f);
                    532:                return 0;
                    533:        }
                    534:
1.4       deraadt   535:        assert(p->rootfd != -1);
1.1       benno     536:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.17      benno     537:
1.4       deraadt   538:        if (rc == -1 && errno != ENOENT) {
1.21      benno     539:                ERR("%s: fstatat", f->path);
1.1       benno     540:                return -1;
1.28      claudio   541:        }
                    542:        if (rc != -1 && !S_ISDIR(st.st_mode)) {
1.21      benno     543:                ERRX("%s: not a directory", f->path);
1.1       benno     544:                return -1;
1.4       deraadt   545:        } else if (rc != -1) {
1.2       benno     546:                /*
1.1       benno     547:                 * FIXME: we should fchmod the permissions here as well,
                    548:                 * as we may locally have shut down writing into the
                    549:                 * directory and that doesn't work.
                    550:                 */
1.21      benno     551:                LOG3("%s: updating directory", f->path);
1.1       benno     552:                return 0;
                    553:        }
                    554:
                    555:        /*
                    556:         * We want to make the directory with default permissions (using
                    557:         * our old umask, which we've since unset), then adjust
                    558:         * permissions (assuming preserve_perms or new) afterward in
                    559:         * case it's u-w or something.
                    560:         */
                    561:
1.21      benno     562:        LOG3("%s: creating directory", f->path);
1.4       deraadt   563:        if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) {
1.21      benno     564:                ERR("%s: mkdirat", f->path);
1.1       benno     565:                return -1;
                    566:        }
                    567:
                    568:        p->newdir[p->idx] = 1;
                    569:        log_dir(sess, f);
                    570:        return 0;
                    571: }
                    572:
                    573: /*
                    574:  * Process the directory time and mode for "idx" in the file list.
                    575:  * Returns zero on failure, non-zero on success.
                    576:  */
                    577: static int
                    578: post_dir(struct sess *sess, const struct upload *u, size_t idx)
                    579: {
                    580:        struct timespec  tv[2];
                    581:        int              rc;
                    582:        struct stat      st;
                    583:        const struct flist *f;
                    584:
                    585:        f = &u->fl[idx];
                    586:        assert(S_ISDIR(f->st.mode));
                    587:
                    588:        /* We already warned about the directory in pre_process_dir(). */
                    589:
1.3       deraadt   590:        if (!sess->opts->recursive)
1.1       benno     591:                return 1;
1.25      claudio   592:        if (sess->opts->dry_run)
1.1       benno     593:                return 1;
                    594:
1.4       deraadt   595:        if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
1.21      benno     596:                ERR("%s: fstatat", f->path);
1.1       benno     597:                return 0;
1.25      claudio   598:        }
                    599:        if (!S_ISDIR(st.st_mode)) {
1.21      benno     600:                WARNX("%s: not a directory", f->path);
1.1       benno     601:                return 0;
                    602:        }
                    603:
1.2       benno     604:        /*
1.1       benno     605:         * Update the modification time if we're a new directory *or* if
                    606:         * we're preserving times and the time has changed.
1.6       florian   607:         * FIXME: run rsync_set_metadata()?
1.1       benno     608:         */
                    609:
1.2       benno     610:        if (u->newdir[idx] ||
                    611:            (sess->opts->preserve_times &&
1.1       benno     612:             st.st_mtime != f->st.mtime)) {
                    613:                tv[0].tv_sec = time(NULL);
                    614:                tv[0].tv_nsec = 0;
                    615:                tv[1].tv_sec = f->st.mtime;
                    616:                tv[1].tv_nsec = 0;
                    617:                rc = utimensat(u->rootfd, f->path, tv, 0);
1.4       deraadt   618:                if (rc == -1) {
1.21      benno     619:                        ERR("%s: utimensat", f->path);
1.1       benno     620:                        return 0;
                    621:                }
1.21      benno     622:                LOG4("%s: updated date", f->path);
1.1       benno     623:        }
                    624:
                    625:        /*
                    626:         * Update the mode if we're a new directory *or* if we're
                    627:         * preserving modes and it has changed.
                    628:         */
                    629:
1.2       benno     630:        if (u->newdir[idx] ||
1.20      deraadt   631:            (sess->opts->preserve_perms && st.st_mode != f->st.mode)) {
1.1       benno     632:                rc = fchmodat(u->rootfd, f->path, f->st.mode, 0);
1.4       deraadt   633:                if (rc == -1) {
1.21      benno     634:                        ERR("%s: fchmodat", f->path);
1.1       benno     635:                        return 0;
                    636:                }
1.21      benno     637:                LOG4("%s: updated mode", f->path);
1.1       benno     638:        }
                    639:
                    640:        return 1;
                    641: }
                    642:
                    643: /*
                    644:  * Try to open the file at the current index.
1.25      claudio   645:  * If the file does not exist, returns with >0.
1.1       benno     646:  * Return <0 on failure, 0 on success w/nothing to be done, >0 on
                    647:  * success and the file needs attention.
                    648:  */
                    649: static int
1.25      claudio   650: pre_file(const struct upload *p, int *filefd, struct stat *st,
                    651:     struct sess *sess)
1.1       benno     652: {
                    653:        const struct flist *f;
1.26      claudio   654:        int rc;
1.1       benno     655:
                    656:        f = &p->fl[p->idx];
                    657:        assert(S_ISREG(f->st.mode));
                    658:
                    659:        if (sess->opts->dry_run) {
                    660:                log_file(sess, f);
1.3       deraadt   661:                if (!io_write_int(sess, p->fdout, p->idx)) {
1.21      benno     662:                        ERRX1("io_write_int");
1.1       benno     663:                        return -1;
                    664:                }
                    665:                return 0;
                    666:        }
                    667:
                    668:        /*
                    669:         * For non dry-run cases, we'll write the acknowledgement later
1.25      claudio   670:         * in the rsync_uploader() function.
1.1       benno     671:         */
                    672:
1.26      claudio   673:        *filefd = -1;
                    674:        rc = fstatat(p->rootfd, f->path, st, AT_SYMLINK_NOFOLLOW);
1.25      claudio   675:
1.26      claudio   676:        if (rc == -1) {
                    677:                if (errno == ENOENT)
                    678:                        return 1;
                    679:
                    680:                ERR("%s: fstatat", f->path);
1.25      claudio   681:                return -1;
                    682:        }
1.28      claudio   683:        if (!S_ISREG(st->st_mode)) {
1.26      claudio   684:                if (S_ISDIR(st->st_mode) &&
                    685:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
                    686:                        ERR("%s: unlinkat", f->path);
                    687:                        return -1;
                    688:                }
1.1       benno     689:                return 1;
1.25      claudio   690:        }
                    691:
1.28      claudio   692:        /* quick check if file is the same */
1.25      claudio   693:        if (st->st_size == f->st.size &&
                    694:            st->st_mtime == f->st.mtime) {
                    695:                LOG3("%s: skipping: up to date", f->path);
1.26      claudio   696:                if (!rsync_set_metadata_at(sess, 0, p->rootfd, f, f->path)) {
1.25      claudio   697:                        ERRX1("rsync_set_metadata");
                    698:                        return -1;
                    699:                }
                    700:                return 0;
                    701:        }
                    702:
1.26      claudio   703:        *filefd = openat(p->rootfd, f->path, O_RDONLY | O_NOFOLLOW, 0);
                    704:        if (*filefd == -1 && errno != ENOENT) {
                    705:                ERR("%s: openat", f->path);
                    706:                return -1;
                    707:        }
                    708:
1.25      claudio   709:        /* file needs attention */
                    710:        return 1;
1.1       benno     711: }
                    712:
                    713: /*
                    714:  * Allocate an uploader object in the correct state to start.
                    715:  * Returns NULL on failure or the pointer otherwise.
                    716:  * On success, upload_free() must be called with the allocated pointer.
                    717:  */
                    718: struct upload *
1.22      benno     719: upload_alloc(const char *root, int rootfd, int fdout,
1.1       benno     720:        size_t clen, const struct flist *fl, size_t flsz, mode_t msk)
                    721: {
                    722:        struct upload   *p;
                    723:
1.4       deraadt   724:        if ((p = calloc(1, sizeof(struct upload))) == NULL) {
1.21      benno     725:                ERR("calloc");
1.1       benno     726:                return NULL;
                    727:        }
                    728:
                    729:        p->state = UPLOAD_FIND_NEXT;
                    730:        p->oumask = msk;
1.11      florian   731:        p->root = strdup(root);
                    732:        if (p->root == NULL) {
1.21      benno     733:                ERR("strdup");
1.11      florian   734:                free(p);
                    735:                return NULL;
                    736:        }
1.1       benno     737:        p->rootfd = rootfd;
                    738:        p->csumlen = clen;
                    739:        p->fdout = fdout;
                    740:        p->fl = fl;
                    741:        p->flsz = flsz;
                    742:        p->newdir = calloc(flsz, sizeof(int));
1.4       deraadt   743:        if (p->newdir == NULL) {
1.21      benno     744:                ERR("calloc");
1.11      florian   745:                free(p->root);
1.1       benno     746:                free(p);
                    747:                return NULL;
                    748:        }
                    749:        return p;
                    750: }
                    751:
                    752: /*
                    753:  * Perform all cleanups and free.
                    754:  * Passing a NULL to this function is ok.
                    755:  */
                    756: void
                    757: upload_free(struct upload *p)
                    758: {
                    759:
1.4       deraadt   760:        if (p == NULL)
1.1       benno     761:                return;
1.11      florian   762:        free(p->root);
1.1       benno     763:        free(p->newdir);
                    764:        free(p->buf);
                    765:        free(p);
                    766: }
                    767:
                    768: /*
                    769:  * Iterates through all available files and conditionally gets the file
                    770:  * ready for processing to check whether it's up to date.
                    771:  * If not up to date or empty, sends file information to the sender.
                    772:  * If returns 0, we've processed all files there are to process.
                    773:  * If returns >0, we're waiting for POLLIN or POLLOUT data.
                    774:  * Otherwise returns <0, which is an error.
                    775:  */
                    776: int
1.2       benno     777: rsync_uploader(struct upload *u, int *fileinfd,
1.1       benno     778:        struct sess *sess, int *fileoutfd)
                    779: {
1.5       florian   780:        struct blkset       blk;
                    781:        struct stat         st;
1.23      benno     782:        void               *mbuf, *bufp;
                    783:        ssize_t             msz;
                    784:        size_t              i, pos, sz;
1.5       florian   785:        off_t               offs;
                    786:        int                 c;
1.1       benno     787:
1.26      claudio   788:        /* Once finished this should never get called again. */
1.4       deraadt   789:        assert(u->state != UPLOAD_FINISHED);
1.1       benno     790:
                    791:        /*
                    792:         * If we have an upload in progress, then keep writing until the
                    793:         * buffer has been fully written.
                    794:         * We must only have the output file descriptor working and also
                    795:         * have a valid buffer to write.
                    796:         */
                    797:
1.25      claudio   798:        if (u->state == UPLOAD_WRITE) {
1.14      deraadt   799:                assert(u->buf != NULL);
1.4       deraadt   800:                assert(*fileoutfd != -1);
                    801:                assert(*fileinfd == -1);
1.1       benno     802:
                    803:                /*
                    804:                 * Unfortunately, we need to chunk these: if we're
                    805:                 * the server side of things, then we're multiplexing
                    806:                 * output and need to wrap this in chunks.
                    807:                 * This is a major deficiency of rsync.
                    808:                 * FIXME: add a "fast-path" mode that simply dumps out
                    809:                 * the buffer non-blocking if we're not mplexing.
                    810:                 */
                    811:
                    812:                if (u->bufpos < u->bufsz) {
                    813:                        sz = MAX_CHUNK < (u->bufsz - u->bufpos) ?
                    814:                                MAX_CHUNK : (u->bufsz - u->bufpos);
1.2       benno     815:                        c = io_write_buf(sess, u->fdout,
1.1       benno     816:                                u->buf + u->bufpos, sz);
1.4       deraadt   817:                        if (c == 0) {
1.21      benno     818:                                ERRX1("io_write_nonblocking");
1.1       benno     819:                                return -1;
                    820:                        }
                    821:                        u->bufpos += sz;
                    822:                        if (u->bufpos < u->bufsz)
                    823:                                return 1;
                    824:                }
                    825:
1.2       benno     826:                /*
1.1       benno     827:                 * Let the UPLOAD_FIND_NEXT state handle things if we
                    828:                 * finish, as we'll need to write a POLLOUT message and
                    829:                 * not have a writable descriptor yet.
                    830:                 */
                    831:
                    832:                u->state = UPLOAD_FIND_NEXT;
                    833:                u->idx++;
                    834:                return 1;
                    835:        }
                    836:
                    837:        /*
                    838:         * If we invoke the uploader without a file currently open, then
                    839:         * we iterate through til the next available regular file and
                    840:         * start the opening process.
                    841:         * This means we must have the output file descriptor working.
                    842:         */
                    843:
1.4       deraadt   844:        if (u->state == UPLOAD_FIND_NEXT) {
                    845:                assert(*fileinfd == -1);
                    846:                assert(*fileoutfd != -1);
1.1       benno     847:
                    848:                for ( ; u->idx < u->flsz; u->idx++) {
                    849:                        if (S_ISDIR(u->fl[u->idx].st.mode))
                    850:                                c = pre_dir(u, sess);
                    851:                        else if (S_ISLNK(u->fl[u->idx].st.mode))
                    852:                                c = pre_link(u, sess);
                    853:                        else if (S_ISREG(u->fl[u->idx].st.mode))
1.25      claudio   854:                                c = pre_file(u, fileinfd, &st, sess);
1.11      florian   855:                        else if (S_ISBLK(u->fl[u->idx].st.mode) ||
                    856:                            S_ISCHR(u->fl[u->idx].st.mode))
                    857:                                c = pre_dev(u, sess);
                    858:                        else if (S_ISFIFO(u->fl[u->idx].st.mode))
                    859:                                c = pre_fifo(u, sess);
                    860:                        else if (S_ISSOCK(u->fl[u->idx].st.mode))
                    861:                                c = pre_sock(u, sess);
1.1       benno     862:                        else
                    863:                                c = 0;
                    864:
                    865:                        if (c < 0)
                    866:                                return -1;
                    867:                        else if (c > 0)
                    868:                                break;
                    869:                }
                    870:
1.2       benno     871:                /*
1.1       benno     872:                 * Whether we've finished writing files or not, we
                    873:                 * disable polling on the output channel.
                    874:                 */
                    875:
                    876:                *fileoutfd = -1;
                    877:                if (u->idx == u->flsz) {
1.4       deraadt   878:                        assert(*fileinfd == -1);
1.3       deraadt   879:                        if (!io_write_int(sess, u->fdout, -1)) {
1.21      benno     880:                                ERRX1("io_write_int");
1.1       benno     881:                                return -1;
                    882:                        }
                    883:                        u->state = UPLOAD_FINISHED;
1.21      benno     884:                        LOG4("uploader: finished");
1.1       benno     885:                        return 0;
                    886:                }
                    887:
                    888:                /* Go back to the event loop, if necessary. */
                    889:
1.25      claudio   890:                u->state = UPLOAD_WRITE;
1.1       benno     891:        }
                    892:
                    893:        /* Initialies our blocks. */
                    894:
1.25      claudio   895:        assert(u->state == UPLOAD_WRITE);
1.1       benno     896:        memset(&blk, 0, sizeof(struct blkset));
                    897:        blk.csum = u->csumlen;
                    898:
1.4       deraadt   899:        if (*fileinfd != -1 && st.st_size > 0) {
1.23      benno     900:                init_blkset(&blk, st.st_size);
                    901:                assert(blk.blksz);
                    902:
                    903:                blk.blks = calloc(blk.blksz, sizeof(struct blk));
                    904:                if (blk.blks == NULL) {
                    905:                        ERR("calloc");
1.1       benno     906:                        close(*fileinfd);
                    907:                        *fileinfd = -1;
                    908:                        return -1;
                    909:                }
                    910:
1.25      claudio   911:                if ((mbuf = malloc(blk.len)) == NULL) {
                    912:                        ERR("malloc");
1.1       benno     913:                        close(*fileinfd);
                    914:                        *fileinfd = -1;
1.27      claudio   915:                        free(blk.blks);
1.1       benno     916:                        return -1;
                    917:                }
                    918:
                    919:                offs = 0;
1.23      benno     920:                i = 0;
                    921:                do {
                    922:                        msz = pread(*fileinfd, mbuf, blk.len, offs);
1.25      claudio   923:                        if ((size_t)msz != blk.len && (size_t)msz != blk.rem) {
1.23      benno     924:                                ERR("pread");
                    925:                                close(*fileinfd);
                    926:                                *fileinfd = -1;
1.25      claudio   927:                                free(mbuf);
1.27      claudio   928:                                free(blk.blks);
1.23      benno     929:                                return -1;
                    930:                        }
                    931:                        init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess);
1.1       benno     932:                        offs += blk.len;
1.23      benno     933:                        LOG3(
                    934:                            "i=%ld, offs=%lld, msz=%ld, blk.len=%lu, blk.rem=%lu",
                    935:                            i, offs, msz, blk.len, blk.rem);
                    936:                        i++;
                    937:                } while (i < blk.blksz);
1.1       benno     938:
1.25      claudio   939:                free(mbuf);
1.1       benno     940:                close(*fileinfd);
                    941:                *fileinfd = -1;
1.21      benno     942:                LOG3("%s: mapped %jd B with %zu blocks",
1.19      deraadt   943:                    u->fl[u->idx].path, (intmax_t)blk.size,
                    944:                    blk.blksz);
1.1       benno     945:        } else {
1.4       deraadt   946:                if (*fileinfd != -1) {
1.1       benno     947:                        close(*fileinfd);
                    948:                        *fileinfd = -1;
                    949:                }
                    950:                blk.len = MAX_CHUNK; /* Doesn't matter. */
1.21      benno     951:                LOG3("%s: not mapped", u->fl[u->idx].path);
1.1       benno     952:        }
                    953:
1.4       deraadt   954:        assert(*fileinfd == -1);
1.1       benno     955:
                    956:        /* Make sure the block metadata buffer is big enough. */
                    957:
1.2       benno     958:        u->bufsz =
1.1       benno     959:             sizeof(int32_t) + /* identifier */
                    960:             sizeof(int32_t) + /* block count */
                    961:             sizeof(int32_t) + /* block length */
                    962:             sizeof(int32_t) + /* checksum length */
                    963:             sizeof(int32_t) + /* block remainder */
1.2       benno     964:             blk.blksz *
1.1       benno     965:             (sizeof(int32_t) + /* short checksum */
                    966:              blk.csum); /* long checksum */
                    967:
                    968:        if (u->bufsz > u->bufmax) {
1.4       deraadt   969:                if ((bufp = realloc(u->buf, u->bufsz)) == NULL) {
1.21      benno     970:                        ERR("realloc");
1.27      claudio   971:                        free(blk.blks);
1.1       benno     972:                        return -1;
                    973:                }
                    974:                u->buf = bufp;
                    975:                u->bufmax = u->bufsz;
                    976:        }
                    977:
                    978:        u->bufpos = pos = 0;
1.22      benno     979:        io_buffer_int(u->buf, &pos, u->bufsz, u->idx);
                    980:        io_buffer_int(u->buf, &pos, u->bufsz, blk.blksz);
                    981:        io_buffer_int(u->buf, &pos, u->bufsz, blk.len);
                    982:        io_buffer_int(u->buf, &pos, u->bufsz, blk.csum);
                    983:        io_buffer_int(u->buf, &pos, u->bufsz, blk.rem);
1.1       benno     984:        for (i = 0; i < blk.blksz; i++) {
1.22      benno     985:                io_buffer_int(u->buf, &pos, u->bufsz,
1.1       benno     986:                        blk.blks[i].chksum_short);
1.22      benno     987:                io_buffer_buf(u->buf, &pos, u->bufsz,
1.1       benno     988:                        blk.blks[i].chksum_long, blk.csum);
                    989:        }
                    990:        assert(pos == u->bufsz);
                    991:
                    992:        /* Reenable the output poller and clean up. */
                    993:
                    994:        *fileoutfd = u->fdout;
                    995:        free(blk.blks);
                    996:        return 1;
                    997: }
                    998:
                    999: /*
                   1000:  * Fix up the directory permissions and times post-order.
                   1001:  * We can't fix up directory permissions in place because the server may
                   1002:  * want us to have overly-tight permissions---say, those that don't
                   1003:  * allow writing into the directory.
                   1004:  * We also need to do our directory times post-order because making
                   1005:  * files within the directory will change modification times.
                   1006:  * Returns zero on failure, non-zero on success.
                   1007:  */
                   1008: int
                   1009: rsync_uploader_tail(struct upload *u, struct sess *sess)
                   1010: {
                   1011:        size_t   i;
                   1012:
                   1013:
1.3       deraadt  1014:        if (!sess->opts->preserve_times &&
1.20      deraadt  1015:            !sess->opts->preserve_perms)
1.1       benno    1016:                return 1;
                   1017:
1.21      benno    1018:        LOG2("fixing up directory times and permissions");
1.1       benno    1019:
                   1020:        for (i = 0; i < u->flsz; i++)
                   1021:                if (S_ISDIR(u->fl[i].st.mode))
1.3       deraadt  1022:                        if (!post_dir(sess, u, i))
1.1       benno    1023:                                return 0;
                   1024:
                   1025:        return 1;
                   1026: }