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

1.24.2.1! benno       1: /*     $Id: uploader.c,v 1.24 2021/03/22 11:20:04 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>
1.24.2.1! benno      22: #include <err.h>
1.1       benno      23: #include <errno.h>
                     24: #include <fcntl.h>
                     25: #include <inttypes.h>
                     26: #include <math.h>
                     27: #include <stdio.h>
                     28: #include <stdlib.h>
                     29: #include <string.h>
                     30: #include <time.h>
                     31: #include <unistd.h>
                     32:
                     33: #include "extern.h"
                     34:
                     35: enum   uploadst {
                     36:        UPLOAD_FIND_NEXT = 0, /* find next to upload to sender */
1.24.2.1! benno      37:        UPLOAD_WRITE, /* wait to write to sender */
1.1       benno      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 */
1.11      florian    53:        char               *root; /* destination directory path */
1.1       benno      54:        int                 rootfd; /* destination directory */
                     55:        size_t              csumlen; /* checksum length */
                     56:        int                 fdout; /* write descriptor to sender */
                     57:        const struct flist *fl; /* file list */
                     58:        size_t              flsz; /* size of file list */
                     59:        int                *newdir; /* non-zero if mkdir'd */
                     60: };
                     61:
                     62: /*
                     63:  * Log a directory by emitting the file and a trailing slash, just to
                     64:  * show the operator that we're a directory.
                     65:  */
                     66: static void
                     67: log_dir(struct sess *sess, const struct flist *f)
                     68: {
                     69:        size_t   sz;
                     70:
                     71:        if (sess->opts->server)
                     72:                return;
                     73:        sz = strlen(f->path);
                     74:        assert(sz > 0);
1.21      benno      75:        LOG1("%s%s", f->path, (f->path[sz - 1] == '/') ? "" : "/");
1.1       benno      76: }
                     77:
                     78: /*
                     79:  * Log a link by emitting the file and the target, just to show the
                     80:  * operator that we're a link.
                     81:  */
                     82: static void
1.24.2.1! benno      83: log_symlink(struct sess *sess, const struct flist *f)
1.1       benno      84: {
                     85:
1.3       deraadt    86:        if (!sess->opts->server)
1.21      benno      87:                LOG1("%s -> %s", f->path, f->link);
1.1       benno      88: }
                     89:
                     90: /*
                     91:  * Simply log the filename.
                     92:  */
                     93: static void
                     94: log_file(struct sess *sess, const struct flist *f)
                     95: {
                     96:
1.3       deraadt    97:        if (!sess->opts->server)
1.21      benno      98:                LOG1("%s", f->path);
1.1       benno      99: }
                    100:
                    101: /*
                    102:  * Prepare the overall block set's metadata.
                    103:  * We always have at least one block.
                    104:  * The block size is an important part of the algorithm.
                    105:  * I use the same heuristic as the reference rsync, but implemented in a
                    106:  * bit more of a straightforward way.
                    107:  * In general, the individual block length is the rounded square root of
                    108:  * the total file size.
                    109:  * The minimum block length is 700.
                    110:  */
                    111: static void
                    112: init_blkset(struct blkset *p, off_t sz)
                    113: {
                    114:        double   v;
                    115:
                    116:        if (sz >= (BLOCK_SIZE_MIN * BLOCK_SIZE_MIN)) {
                    117:                /* Simple rounded-up integer square root. */
                    118:
                    119:                v = sqrt(sz);
                    120:                p->len = ceil(v);
                    121:
1.2       benno     122:                /*
1.1       benno     123:                 * Always be a multiple of eight.
                    124:                 * There's no reason to do this, but rsync does.
                    125:                 */
                    126:
                    127:                if ((p->len % 8) > 0)
                    128:                        p->len += 8 - (p->len % 8);
                    129:        } else
                    130:                p->len = BLOCK_SIZE_MIN;
                    131:
                    132:        p->size = sz;
1.4       deraadt   133:        if ((p->blksz = sz / p->len) == 0)
1.1       benno     134:                p->rem = sz;
                    135:        else
                    136:                p->rem = sz % p->len;
                    137:
                    138:        /* If we have a remainder, then we need an extra block. */
                    139:
                    140:        if (p->rem)
                    141:                p->blksz++;
                    142: }
                    143:
                    144: /*
                    145:  * For each block, prepare the block's metadata.
                    146:  * We use the mapped "map" file to set our checksums.
                    147:  */
                    148: static void
                    149: init_blk(struct blk *p, const struct blkset *set, off_t offs,
                    150:        size_t idx, const void *map, const struct sess *sess)
                    151: {
                    152:
1.24      claudio   153:        p->idx = idx;
1.1       benno     154:        /* Block length inherits for all but the last. */
                    155:        p->len = idx < set->blksz - 1 ? set->len : set->rem;
                    156:        p->offs = offs;
                    157:
1.23      benno     158:        p->chksum_short = hash_fast(map, p->len);
                    159:        hash_slow(map, p->len, p->chksum_long, sess);
1.1       benno     160: }
                    161:
                    162: /*
1.17      benno     163:  * Handle a symbolic link.
                    164:  * If we encounter directories existing in the symbolic link's place,
                    165:  * then try to unlink the directory.
                    166:  * Otherwise, simply overwrite with the symbolic link by renaming.
1.1       benno     167:  * Return <0 on failure 0 on success.
                    168:  */
                    169: static int
1.24.2.1! benno     170: pre_symlink(struct upload *p, struct sess *sess)
1.1       benno     171: {
1.9       florian   172:        struct stat              st;
                    173:        const struct flist      *f;
                    174:        int                      rc, newlink = 0, updatelink = 0;
1.11      florian   175:        char                    *b, *temp = NULL;
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.21      benno     181:                WARNX("%s: ignoring symlink", f->path);
1.1       benno     182:                return 0;
1.24.2.1! benno     183:        }
        !           184:        if (sess->opts->dry_run) {
        !           185:                log_symlink(sess, f);
1.1       benno     186:                return 0;
                    187:        }
                    188:
1.17      benno     189:        /*
                    190:         * See if the symlink already exists.
                    191:         * If it's a directory, then try to unlink the directory prior
                    192:         * to overwriting with a symbolic link.
                    193:         * If it's a non-directory, we just overwrite it.
                    194:         */
1.1       benno     195:
1.4       deraadt   196:        assert(p->rootfd != -1);
1.1       benno     197:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.24.2.1! benno     198:
        !           199:        if (rc == -1 && errno != ENOENT) {
        !           200:                ERR("%s: fstatat", f->path);
        !           201:                return -1;
        !           202:        }
1.4       deraadt   203:        if (rc != -1 && !S_ISLNK(st.st_mode)) {
1.17      benno     204:                if (S_ISDIR(st.st_mode) &&
                    205:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
1.21      benno     206:                        ERR("%s: unlinkat", f->path);
1.17      benno     207:                        return -1;
1.9       florian   208:                }
1.17      benno     209:                rc = -1;
1.1       benno     210:        }
                    211:
                    212:        /*
                    213:         * If the symbolic link already exists, then make sure that it
                    214:         * points to the correct place.
                    215:         */
                    216:
1.9       florian   217:        if (rc != -1) {
1.22      benno     218:                b = symlinkat_read(p->rootfd, f->path);
1.4       deraadt   219:                if (b == NULL) {
1.21      benno     220:                        ERRX1("symlinkat_read");
1.1       benno     221:                        return -1;
                    222:                }
                    223:                if (strcmp(f->link, b)) {
                    224:                        free(b);
                    225:                        b = NULL;
1.21      benno     226:                        LOG3("%s: updating symlink: %s", f->path, f->link);
1.9       florian   227:                        updatelink = 1;
1.2       benno     228:                }
1.1       benno     229:                free(b);
1.9       florian   230:                b = NULL;
                    231:        }
                    232:
1.17      benno     233:        /*
                    234:         * Create the temporary file as a symbolic link, then rename the
                    235:         * temporary file as the real one, overwriting anything there.
                    236:         */
                    237:
1.9       florian   238:        if (rc == -1 || updatelink) {
1.21      benno     239:                LOG3("%s: creating symlink: %s", f->path, f->link);
1.22      benno     240:                if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
1.21      benno     241:                        ERRX1("mktemplate");
1.9       florian   242:                        return -1;
                    243:                }
1.11      florian   244:                if (mkstemplinkat(f->link, p->rootfd, temp) == NULL) {
1.21      benno     245:                        ERR("mkstemplinkat");
1.11      florian   246:                        free(temp);
1.9       florian   247:                        return -1;
                    248:                }
                    249:                newlink = 1;
1.1       benno     250:        }
                    251:
1.17      benno     252:        rsync_set_metadata_at(sess, newlink,
                    253:                p->rootfd, f, newlink ? temp : f->path);
1.11      florian   254:
                    255:        if (newlink) {
                    256:                if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
1.21      benno     257:                        ERR("%s: renameat %s", temp, f->path);
1.11      florian   258:                        (void)unlinkat(p->rootfd, temp, 0);
                    259:                        free(temp);
                    260:                        return -1;
                    261:                }
                    262:                free(temp);
                    263:        }
                    264:
1.24.2.1! benno     265:        log_symlink(sess, f);
1.11      florian   266:        return 0;
                    267: }
                    268:
                    269: /*
1.24.2.1! benno     270:  * See pre_symlink(), but for devices.
1.17      benno     271:  * FIXME: this is very similar to the other pre_xxx() functions.
1.11      florian   272:  * Return <0 on failure 0 on success.
                    273:  */
                    274: static int
                    275: pre_dev(struct upload *p, struct sess *sess)
                    276: {
                    277:        struct stat              st;
                    278:        const struct flist      *f;
                    279:        int                      rc, newdev = 0, updatedev = 0;
                    280:        char                    *temp = NULL;
                    281:
                    282:        f = &p->fl[p->idx];
                    283:        assert(S_ISBLK(f->st.mode) || S_ISCHR(f->st.mode));
                    284:
                    285:        if (!sess->opts->devices || getuid() != 0) {
1.21      benno     286:                WARNX("skipping non-regular file %s", f->path);
1.11      florian   287:                return 0;
1.24.2.1! benno     288:        }
        !           289:        if (sess->opts->dry_run) {
1.11      florian   290:                log_file(sess, f);
                    291:                return 0;
                    292:        }
                    293:
1.17      benno     294:        /*
                    295:         * See if the dev already exists.
                    296:         * If a non-device exists in its place, we'll replace that.
                    297:         * If it replaces a directory, remove the directory first.
                    298:         */
                    299:
1.16      benno     300:        assert(p->rootfd != -1);
1.11      florian   301:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
                    302:
1.24.2.1! benno     303:        if (rc == -1 && errno != ENOENT) {
        !           304:                ERR("%s: fstatat", f->path);
        !           305:                return -1;
        !           306:        }
1.11      florian   307:        if (rc != -1 && !(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) {
1.17      benno     308:                if (S_ISDIR(st.st_mode) &&
                    309:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
1.21      benno     310:                        ERR("%s: unlinkat", f->path);
1.17      benno     311:                        return -1;
1.11      florian   312:                }
1.17      benno     313:                rc = -1;
1.11      florian   314:        }
                    315:
1.17      benno     316:        /* Make sure existing device is of the correct type. */
1.1       benno     317:
1.11      florian   318:        if (rc != -1) {
                    319:                if ((f->st.mode & (S_IFCHR|S_IFBLK)) !=
1.17      benno     320:                    (st.st_mode & (S_IFCHR|S_IFBLK)) ||
                    321:                    f->st.rdev != st.st_rdev) {
1.21      benno     322:                        LOG3("%s: updating device", f->path);
1.11      florian   323:                        updatedev = 1;
                    324:                }
                    325:        }
                    326:
                    327:        if (rc == -1 || updatedev) {
                    328:                newdev = 1;
1.22      benno     329:                if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
1.21      benno     330:                        ERRX1("mktemplate");
1.11      florian   331:                        return -1;
                    332:                }
1.17      benno     333:                if (mkstempnodat(p->rootfd, temp,
                    334:                    f->st.mode & (S_IFCHR|S_IFBLK), f->st.rdev) == NULL) {
1.21      benno     335:                        ERR("mkstempnodat");
1.11      florian   336:                        free(temp);
                    337:                        return -1;
                    338:                }
                    339:        }
                    340:
1.17      benno     341:        rsync_set_metadata_at(sess, newdev,
1.22      benno     342:            p->rootfd, f, newdev ? temp : f->path);
1.11      florian   343:
                    344:        if (newdev) {
                    345:                if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
1.21      benno     346:                        ERR("%s: renameat %s", temp, f->path);
1.11      florian   347:                        (void)unlinkat(p->rootfd, temp, 0);
                    348:                        free(temp);
                    349:                        return -1;
                    350:                }
                    351:                free(temp);
                    352:        }
1.17      benno     353:
1.11      florian   354:        log_file(sess, f);
                    355:        return 0;
                    356: }
                    357:
                    358: /*
1.24.2.1! benno     359:  * See pre_symlink(), but for FIFOs.
1.17      benno     360:  * FIXME: this is very similar to the other pre_xxx() functions.
1.11      florian   361:  * Return <0 on failure 0 on success.
                    362:  */
                    363: static int
                    364: pre_fifo(struct upload *p, struct sess *sess)
                    365: {
                    366:        struct stat              st;
                    367:        const struct flist      *f;
                    368:        int                      rc, newfifo = 0;
                    369:        char                    *temp = NULL;
                    370:
                    371:        f = &p->fl[p->idx];
                    372:        assert(S_ISFIFO(f->st.mode));
                    373:
                    374:        if (!sess->opts->specials) {
1.21      benno     375:                WARNX("skipping non-regular file %s", f->path);
1.11      florian   376:                return 0;
1.24.2.1! benno     377:        }
        !           378:        if (sess->opts->dry_run) {
1.11      florian   379:                log_file(sess, f);
                    380:                return 0;
                    381:        }
                    382:
1.17      benno     383:        /*
                    384:         * See if the fifo already exists.
                    385:         * If it exists as a non-FIFO, unlink it (if a directory) then
                    386:         * mark it from replacement.
                    387:         */
                    388:
1.16      benno     389:        assert(p->rootfd != -1);
1.11      florian   390:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.8       deraadt   391:
1.24.2.1! benno     392:        if (rc == -1 && errno != ENOENT) {
        !           393:                ERR("%s: fstatat", f->path);
        !           394:                return -1;
        !           395:        }
1.11      florian   396:        if (rc != -1 && !S_ISFIFO(st.st_mode)) {
1.17      benno     397:                if (S_ISDIR(st.st_mode) &&
                    398:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
1.21      benno     399:                        ERR("%s: unlinkat", f->path);
1.17      benno     400:                        return -1;
1.11      florian   401:                }
1.17      benno     402:                rc = -1;
1.11      florian   403:        }
                    404:
                    405:        if (rc == -1) {
                    406:                newfifo = 1;
1.22      benno     407:                if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
1.21      benno     408:                        ERRX1("mktemplate");
1.11      florian   409:                        return -1;
                    410:                }
                    411:                if (mkstempfifoat(p->rootfd, temp) == NULL) {
1.21      benno     412:                        ERR("mkstempfifoat");
1.11      florian   413:                        free(temp);
1.1       benno     414:                        return -1;
                    415:                }
                    416:        }
1.2       benno     417:
1.17      benno     418:        rsync_set_metadata_at(sess, newfifo,
                    419:                p->rootfd, f, newfifo ? temp : f->path);
1.11      florian   420:
                    421:        if (newfifo) {
                    422:                if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
1.21      benno     423:                        ERR("%s: renameat %s", temp, f->path);
1.11      florian   424:                        (void)unlinkat(p->rootfd, temp, 0);
                    425:                        free(temp);
                    426:                        return -1;
                    427:                }
                    428:                free(temp);
                    429:        }
1.17      benno     430:
1.11      florian   431:        log_file(sess, f);
                    432:        return 0;
                    433: }
1.1       benno     434:
1.11      florian   435: /*
1.24.2.1! benno     436:  * See pre_symlink(), but for socket files.
1.17      benno     437:  * FIXME: this is very similar to the other pre_xxx() functions.
1.11      florian   438:  * Return <0 on failure 0 on success.
                    439:  */
                    440: static int
                    441: pre_sock(struct upload *p, struct sess *sess)
                    442: {
                    443:        struct stat              st;
                    444:        const struct flist      *f;
                    445:        int                      rc, newsock = 0;
                    446:        char                    *temp = NULL;
                    447:
                    448:        f = &p->fl[p->idx];
                    449:        assert(S_ISSOCK(f->st.mode));
                    450:
                    451:        if (!sess->opts->specials) {
1.21      benno     452:                WARNX("skipping non-regular file %s", f->path);
1.11      florian   453:                return 0;
1.24.2.1! benno     454:        }
        !           455:        if (sess->opts->dry_run) {
1.11      florian   456:                log_file(sess, f);
                    457:                return 0;
                    458:        }
                    459:
1.17      benno     460:        /*
                    461:         * See if the fifo already exists.
                    462:         * If it exists as a non-FIFO, unlink it (if a directory) then
                    463:         * mark it from replacement.
                    464:         */
                    465:
1.18      deraadt   466:        assert(p->rootfd != -1);
1.11      florian   467:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
                    468:
1.24.2.1! benno     469:        if (rc == -1 && errno != ENOENT) {
        !           470:                ERR("%s: fstatat", f->path);
        !           471:                return -1;
        !           472:        }
1.11      florian   473:        if (rc != -1 && !S_ISSOCK(st.st_mode)) {
1.17      benno     474:                if (S_ISDIR(st.st_mode) &&
                    475:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
1.21      benno     476:                        ERR("%s: unlinkat", f->path);
1.17      benno     477:                        return -1;
1.11      florian   478:                }
1.17      benno     479:                rc = -1;
1.11      florian   480:        }
                    481:
                    482:        if (rc == -1) {
                    483:                newsock = 1;
1.22      benno     484:                if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
1.21      benno     485:                        ERRX1("mktemplate");
1.11      florian   486:                        return -1;
                    487:                }
                    488:                if (mkstempsock(p->root, temp) == NULL) {
1.21      benno     489:                        ERR("mkstempsock");
1.11      florian   490:                        free(temp);
1.1       benno     491:                        return -1;
                    492:                }
1.9       florian   493:        }
                    494:
1.17      benno     495:        rsync_set_metadata_at(sess, newsock,
                    496:                p->rootfd, f, newsock ? temp : f->path);
1.11      florian   497:
                    498:        if (newsock) {
                    499:                if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
1.21      benno     500:                        ERR("%s: renameat %s", temp, f->path);
1.11      florian   501:                        (void)unlinkat(p->rootfd, temp, 0);
                    502:                        free(temp);
1.9       florian   503:                        return -1;
                    504:                }
1.11      florian   505:                free(temp);
1.1       benno     506:        }
1.17      benno     507:
1.11      florian   508:        log_file(sess, f);
1.1       benno     509:        return 0;
                    510: }
                    511:
                    512: /*
                    513:  * If not found, create the destination directory in prefix order.
                    514:  * Create directories using the existing umask.
                    515:  * Return <0 on failure 0 on success.
                    516:  */
                    517: static int
                    518: pre_dir(const struct upload *p, struct sess *sess)
                    519: {
                    520:        struct stat      st;
1.2       benno     521:        int              rc;
1.1       benno     522:        const struct flist *f;
                    523:
                    524:        f = &p->fl[p->idx];
                    525:        assert(S_ISDIR(f->st.mode));
                    526:
1.3       deraadt   527:        if (!sess->opts->recursive) {
1.21      benno     528:                WARNX("%s: ignoring directory", f->path);
1.1       benno     529:                return 0;
1.24.2.1! benno     530:        }
        !           531:        if (sess->opts->dry_run) {
1.1       benno     532:                log_dir(sess, f);
                    533:                return 0;
                    534:        }
                    535:
1.4       deraadt   536:        assert(p->rootfd != -1);
1.1       benno     537:        rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.17      benno     538:
1.4       deraadt   539:        if (rc == -1 && errno != ENOENT) {
1.21      benno     540:                ERR("%s: fstatat", f->path);
1.1       benno     541:                return -1;
1.24.2.1! benno     542:        }
        !           543:        if (rc != -1 && !S_ISDIR(st.st_mode)) {
1.21      benno     544:                ERRX("%s: not a directory", f->path);
1.1       benno     545:                return -1;
1.4       deraadt   546:        } else if (rc != -1) {
1.2       benno     547:                /*
1.1       benno     548:                 * FIXME: we should fchmod the permissions here as well,
                    549:                 * as we may locally have shut down writing into the
                    550:                 * directory and that doesn't work.
                    551:                 */
1.21      benno     552:                LOG3("%s: updating directory", f->path);
1.1       benno     553:                return 0;
                    554:        }
                    555:
                    556:        /*
                    557:         * We want to make the directory with default permissions (using
                    558:         * our old umask, which we've since unset), then adjust
                    559:         * permissions (assuming preserve_perms or new) afterward in
                    560:         * case it's u-w or something.
                    561:         */
                    562:
1.21      benno     563:        LOG3("%s: creating directory", f->path);
1.4       deraadt   564:        if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) {
1.21      benno     565:                ERR("%s: mkdirat", f->path);
1.1       benno     566:                return -1;
                    567:        }
                    568:
                    569:        p->newdir[p->idx] = 1;
                    570:        log_dir(sess, f);
                    571:        return 0;
                    572: }
                    573:
                    574: /*
                    575:  * Process the directory time and mode for "idx" in the file list.
                    576:  * Returns zero on failure, non-zero on success.
                    577:  */
                    578: static int
                    579: post_dir(struct sess *sess, const struct upload *u, size_t idx)
                    580: {
                    581:        struct timespec  tv[2];
                    582:        int              rc;
                    583:        struct stat      st;
                    584:        const struct flist *f;
                    585:
                    586:        f = &u->fl[idx];
                    587:        assert(S_ISDIR(f->st.mode));
                    588:
                    589:        /* We already warned about the directory in pre_process_dir(). */
                    590:
1.3       deraadt   591:        if (!sess->opts->recursive)
1.1       benno     592:                return 1;
1.24.2.1! benno     593:        if (sess->opts->dry_run)
1.1       benno     594:                return 1;
                    595:
1.4       deraadt   596:        if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
1.21      benno     597:                ERR("%s: fstatat", f->path);
1.1       benno     598:                return 0;
1.24.2.1! benno     599:        }
        !           600:        if (!S_ISDIR(st.st_mode)) {
1.21      benno     601:                WARNX("%s: not a directory", f->path);
1.1       benno     602:                return 0;
                    603:        }
                    604:
1.2       benno     605:        /*
1.1       benno     606:         * Update the modification time if we're a new directory *or* if
                    607:         * we're preserving times and the time has changed.
1.6       florian   608:         * FIXME: run rsync_set_metadata()?
1.1       benno     609:         */
                    610:
1.2       benno     611:        if (u->newdir[idx] ||
                    612:            (sess->opts->preserve_times &&
1.1       benno     613:             st.st_mtime != f->st.mtime)) {
                    614:                tv[0].tv_sec = time(NULL);
                    615:                tv[0].tv_nsec = 0;
                    616:                tv[1].tv_sec = f->st.mtime;
                    617:                tv[1].tv_nsec = 0;
                    618:                rc = utimensat(u->rootfd, f->path, tv, 0);
1.4       deraadt   619:                if (rc == -1) {
1.21      benno     620:                        ERR("%s: utimensat", f->path);
1.1       benno     621:                        return 0;
                    622:                }
1.21      benno     623:                LOG4("%s: updated date", f->path);
1.1       benno     624:        }
                    625:
                    626:        /*
                    627:         * Update the mode if we're a new directory *or* if we're
                    628:         * preserving modes and it has changed.
                    629:         */
                    630:
1.2       benno     631:        if (u->newdir[idx] ||
1.20      deraadt   632:            (sess->opts->preserve_perms && st.st_mode != f->st.mode)) {
1.1       benno     633:                rc = fchmodat(u->rootfd, f->path, f->st.mode, 0);
1.4       deraadt   634:                if (rc == -1) {
1.21      benno     635:                        ERR("%s: fchmodat", f->path);
1.1       benno     636:                        return 0;
                    637:                }
1.21      benno     638:                LOG4("%s: updated mode", f->path);
1.1       benno     639:        }
                    640:
                    641:        return 1;
                    642: }
                    643:
                    644: /*
1.24.2.1! benno     645:  * Check if file exists in the specified root directory.
        !           646:  * Returns:
        !           647:  *    -1 on error
        !           648:  *     0 if file is considered the same
        !           649:  *     1 if file exists and is possible match
        !           650:  *     2 if file exists but quick check failed
        !           651:  *     3 if file does not exist
        !           652:  * The stat pointer st is only valid for 0, 1, and 2 returns.
        !           653:  */
        !           654: static int
        !           655: check_file(int rootfd, const struct flist *f, struct stat *st)
        !           656: {
        !           657:        if (fstatat(rootfd, f->path, st, AT_SYMLINK_NOFOLLOW) == -1) {
        !           658:                if (errno == ENOENT)
        !           659:                        return 3;
        !           660:
        !           661:                ERR("%s: fstatat", f->path);
        !           662:                return -1;
        !           663:        }
        !           664:
        !           665:        /* non-regular file needs attention */
        !           666:        if (!S_ISREG(st->st_mode))
        !           667:                return 2;
        !           668:
        !           669:        /* quick check if file is the same */
        !           670:        /* TODO: add support for --checksum, --size-only and --ignore-times */
        !           671:        if (st->st_size == f->st.size) {
        !           672:                if (st->st_mtime == f->st.mtime)
        !           673:                        return 0;
        !           674:                return 1;
        !           675:        }
        !           676:
        !           677:        /* file needs attention */
        !           678:        return 2;
        !           679: }
        !           680:
        !           681: /*
1.1       benno     682:  * Try to open the file at the current index.
1.24.2.1! benno     683:  * If the file does not exist, returns with >0.
1.1       benno     684:  * Return <0 on failure, 0 on success w/nothing to be done, >0 on
                    685:  * success and the file needs attention.
                    686:  */
                    687: static int
1.24.2.1! benno     688: pre_file(const struct upload *p, int *filefd, off_t *size,
        !           689:     struct sess *sess)
1.1       benno     690: {
                    691:        const struct flist *f;
1.24.2.1! benno     692:        struct stat st;
        !           693:        int i, rc, match = -1;
1.1       benno     694:
                    695:        f = &p->fl[p->idx];
                    696:        assert(S_ISREG(f->st.mode));
                    697:
                    698:        if (sess->opts->dry_run) {
                    699:                log_file(sess, f);
1.3       deraadt   700:                if (!io_write_int(sess, p->fdout, p->idx)) {
1.21      benno     701:                        ERRX1("io_write_int");
1.1       benno     702:                        return -1;
                    703:                }
                    704:                return 0;
                    705:        }
                    706:
1.24.2.1! benno     707:        if (sess->opts->max_size >= 0 && f->st.size > sess->opts->max_size) {
        !           708:                WARNX("skipping over max-size file %s", f->path);
        !           709:                return 0;
        !           710:        }
        !           711:        if (sess->opts->min_size >= 0 && f->st.size < sess->opts->min_size) {
        !           712:                WARNX("skipping under min-size file %s", f->path);
        !           713:                return 0;
        !           714:        }
        !           715:
1.1       benno     716:        /*
                    717:         * For non dry-run cases, we'll write the acknowledgement later
1.24.2.1! benno     718:         * in the rsync_uploader() function.
1.1       benno     719:         */
                    720:
1.24.2.1! benno     721:        *size = 0;
        !           722:        *filefd = -1;
        !           723:
        !           724:        rc = check_file(p->rootfd, f, &st);
        !           725:        if (rc == -1)
        !           726:                return -1;
        !           727:        if (rc == 2 && !S_ISREG(st.st_mode)) {
        !           728:                if (S_ISDIR(st.st_mode) &&
        !           729:                    unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
        !           730:                        ERR("%s: unlinkat", f->path);
        !           731:                        return -1;
        !           732:                }
        !           733:        }
        !           734:        if (rc == 0) {
        !           735:                if (!rsync_set_metadata_at(sess, 0, p->rootfd, f, f->path)) {
        !           736:                        ERRX1("rsync_set_metadata");
        !           737:                        return -1;
        !           738:                }
        !           739:                LOG3("%s: skipping: up to date", f->path);
        !           740:                return 0;
        !           741:        }
        !           742:
        !           743:        /* check alternative locations for better match */
        !           744:        for (i = 0; sess->opts->basedir[i] != NULL; i++) {
        !           745:                const char *root = sess->opts->basedir[i];
        !           746:                int dfd, x;
        !           747:
        !           748:                dfd = openat(p->rootfd, root, O_RDONLY | O_DIRECTORY);
        !           749:                if (dfd == -1)
        !           750:                        err(ERR_FILE_IO, "%s: openat", root);
        !           751:                x = check_file(dfd, f, &st);
        !           752:                /* found a match */
        !           753:                if (x == 0) {
        !           754:                        if (rc >= 0) {
        !           755:                                /* found better match, delete file in rootfd */
        !           756:                                if (unlinkat(p->rootfd, f->path, 0) == -1 &&
        !           757:                                    errno != ENOENT) {
        !           758:                                        ERR("%s: unlinkat", f->path);
        !           759:                                        return -1;
        !           760:                                }
        !           761:                        }
        !           762:                        LOG3("%s: skipping: up to date in %s", f->path, root);
        !           763:                        /* TODO: depending on mode link or copy file */
        !           764:                        close(dfd);
        !           765:                        return 0;
        !           766:                } else if (x == 1 && match == -1) {
        !           767:                        /* found a local file that is a close match */
        !           768:                        match = i;
        !           769:                }
        !           770:                close(dfd);
        !           771:        }
        !           772:        if (match != -1) {
        !           773:                /* copy match from basedir into root as a start point */
        !           774:                copy_file(p->rootfd, sess->opts->basedir[match], f);
        !           775:                if (fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) ==
        !           776:                    -1) {
        !           777:                        ERR("%s: fstatat", f->path);
        !           778:                        return -1;
        !           779:                }
        !           780:        }
        !           781:
        !           782:        *size = st.st_size;
        !           783:        *filefd = openat(p->rootfd, f->path, O_RDONLY | O_NOFOLLOW);
        !           784:        if (*filefd == -1 && errno != ENOENT) {
        !           785:                ERR("%s: openat", f->path);
        !           786:                return -1;
        !           787:        }
        !           788:
        !           789:        /* file needs attention */
        !           790:        return 1;
1.1       benno     791: }
                    792:
                    793: /*
                    794:  * Allocate an uploader object in the correct state to start.
                    795:  * Returns NULL on failure or the pointer otherwise.
                    796:  * On success, upload_free() must be called with the allocated pointer.
                    797:  */
                    798: struct upload *
1.22      benno     799: upload_alloc(const char *root, int rootfd, int fdout,
1.1       benno     800:        size_t clen, const struct flist *fl, size_t flsz, mode_t msk)
                    801: {
                    802:        struct upload   *p;
                    803:
1.4       deraadt   804:        if ((p = calloc(1, sizeof(struct upload))) == NULL) {
1.21      benno     805:                ERR("calloc");
1.1       benno     806:                return NULL;
                    807:        }
                    808:
                    809:        p->state = UPLOAD_FIND_NEXT;
                    810:        p->oumask = msk;
1.11      florian   811:        p->root = strdup(root);
                    812:        if (p->root == NULL) {
1.21      benno     813:                ERR("strdup");
1.11      florian   814:                free(p);
                    815:                return NULL;
                    816:        }
1.1       benno     817:        p->rootfd = rootfd;
                    818:        p->csumlen = clen;
                    819:        p->fdout = fdout;
                    820:        p->fl = fl;
                    821:        p->flsz = flsz;
                    822:        p->newdir = calloc(flsz, sizeof(int));
1.4       deraadt   823:        if (p->newdir == NULL) {
1.21      benno     824:                ERR("calloc");
1.11      florian   825:                free(p->root);
1.1       benno     826:                free(p);
                    827:                return NULL;
                    828:        }
                    829:        return p;
                    830: }
                    831:
                    832: /*
                    833:  * Perform all cleanups and free.
                    834:  * Passing a NULL to this function is ok.
                    835:  */
                    836: void
                    837: upload_free(struct upload *p)
                    838: {
                    839:
1.4       deraadt   840:        if (p == NULL)
1.1       benno     841:                return;
1.11      florian   842:        free(p->root);
1.1       benno     843:        free(p->newdir);
                    844:        free(p->buf);
                    845:        free(p);
                    846: }
                    847:
                    848: /*
                    849:  * Iterates through all available files and conditionally gets the file
                    850:  * ready for processing to check whether it's up to date.
                    851:  * If not up to date or empty, sends file information to the sender.
                    852:  * If returns 0, we've processed all files there are to process.
                    853:  * If returns >0, we're waiting for POLLIN or POLLOUT data.
                    854:  * Otherwise returns <0, which is an error.
                    855:  */
                    856: int
1.2       benno     857: rsync_uploader(struct upload *u, int *fileinfd,
1.1       benno     858:        struct sess *sess, int *fileoutfd)
                    859: {
1.5       florian   860:        struct blkset       blk;
1.23      benno     861:        void               *mbuf, *bufp;
                    862:        ssize_t             msz;
                    863:        size_t              i, pos, sz;
1.24.2.1! benno     864:        off_t               offs, filesize;
1.5       florian   865:        int                 c;
1.1       benno     866:
1.24.2.1! benno     867:        /* Once finished this should never get called again. */
1.4       deraadt   868:        assert(u->state != UPLOAD_FINISHED);
1.1       benno     869:
                    870:        /*
                    871:         * If we have an upload in progress, then keep writing until the
                    872:         * buffer has been fully written.
                    873:         * We must only have the output file descriptor working and also
                    874:         * have a valid buffer to write.
                    875:         */
                    876:
1.24.2.1! benno     877:        if (u->state == UPLOAD_WRITE) {
1.14      deraadt   878:                assert(u->buf != NULL);
1.4       deraadt   879:                assert(*fileoutfd != -1);
                    880:                assert(*fileinfd == -1);
1.1       benno     881:
                    882:                /*
                    883:                 * Unfortunately, we need to chunk these: if we're
                    884:                 * the server side of things, then we're multiplexing
                    885:                 * output and need to wrap this in chunks.
                    886:                 * This is a major deficiency of rsync.
                    887:                 * FIXME: add a "fast-path" mode that simply dumps out
                    888:                 * the buffer non-blocking if we're not mplexing.
                    889:                 */
                    890:
                    891:                if (u->bufpos < u->bufsz) {
                    892:                        sz = MAX_CHUNK < (u->bufsz - u->bufpos) ?
                    893:                                MAX_CHUNK : (u->bufsz - u->bufpos);
1.2       benno     894:                        c = io_write_buf(sess, u->fdout,
1.1       benno     895:                                u->buf + u->bufpos, sz);
1.4       deraadt   896:                        if (c == 0) {
1.21      benno     897:                                ERRX1("io_write_nonblocking");
1.1       benno     898:                                return -1;
                    899:                        }
                    900:                        u->bufpos += sz;
                    901:                        if (u->bufpos < u->bufsz)
                    902:                                return 1;
                    903:                }
                    904:
1.2       benno     905:                /*
1.1       benno     906:                 * Let the UPLOAD_FIND_NEXT state handle things if we
                    907:                 * finish, as we'll need to write a POLLOUT message and
                    908:                 * not have a writable descriptor yet.
                    909:                 */
                    910:
                    911:                u->state = UPLOAD_FIND_NEXT;
                    912:                u->idx++;
                    913:                return 1;
                    914:        }
                    915:
                    916:        /*
                    917:         * If we invoke the uploader without a file currently open, then
                    918:         * we iterate through til the next available regular file and
                    919:         * start the opening process.
                    920:         * This means we must have the output file descriptor working.
                    921:         */
                    922:
1.4       deraadt   923:        if (u->state == UPLOAD_FIND_NEXT) {
                    924:                assert(*fileinfd == -1);
                    925:                assert(*fileoutfd != -1);
1.1       benno     926:
                    927:                for ( ; u->idx < u->flsz; u->idx++) {
                    928:                        if (S_ISDIR(u->fl[u->idx].st.mode))
                    929:                                c = pre_dir(u, sess);
                    930:                        else if (S_ISLNK(u->fl[u->idx].st.mode))
1.24.2.1! benno     931:                                c = pre_symlink(u, sess);
1.1       benno     932:                        else if (S_ISREG(u->fl[u->idx].st.mode))
1.24.2.1! benno     933:                                c = pre_file(u, fileinfd, &filesize, sess);
1.11      florian   934:                        else if (S_ISBLK(u->fl[u->idx].st.mode) ||
                    935:                            S_ISCHR(u->fl[u->idx].st.mode))
                    936:                                c = pre_dev(u, sess);
                    937:                        else if (S_ISFIFO(u->fl[u->idx].st.mode))
                    938:                                c = pre_fifo(u, sess);
                    939:                        else if (S_ISSOCK(u->fl[u->idx].st.mode))
                    940:                                c = pre_sock(u, sess);
1.1       benno     941:                        else
                    942:                                c = 0;
                    943:
                    944:                        if (c < 0)
                    945:                                return -1;
                    946:                        else if (c > 0)
                    947:                                break;
                    948:                }
                    949:
1.2       benno     950:                /*
1.1       benno     951:                 * Whether we've finished writing files or not, we
                    952:                 * disable polling on the output channel.
                    953:                 */
                    954:
                    955:                *fileoutfd = -1;
                    956:                if (u->idx == u->flsz) {
1.4       deraadt   957:                        assert(*fileinfd == -1);
1.3       deraadt   958:                        if (!io_write_int(sess, u->fdout, -1)) {
1.21      benno     959:                                ERRX1("io_write_int");
1.1       benno     960:                                return -1;
                    961:                        }
                    962:                        u->state = UPLOAD_FINISHED;
1.21      benno     963:                        LOG4("uploader: finished");
1.1       benno     964:                        return 0;
                    965:                }
                    966:
                    967:                /* Go back to the event loop, if necessary. */
                    968:
1.24.2.1! benno     969:                u->state = UPLOAD_WRITE;
1.1       benno     970:        }
                    971:
                    972:        /* Initialies our blocks. */
                    973:
1.24.2.1! benno     974:        assert(u->state == UPLOAD_WRITE);
1.1       benno     975:        memset(&blk, 0, sizeof(struct blkset));
                    976:        blk.csum = u->csumlen;
                    977:
1.24.2.1! benno     978:        if (*fileinfd != -1 && filesize > 0) {
        !           979:                init_blkset(&blk, filesize);
1.23      benno     980:                assert(blk.blksz);
                    981:
                    982:                blk.blks = calloc(blk.blksz, sizeof(struct blk));
                    983:                if (blk.blks == NULL) {
                    984:                        ERR("calloc");
1.1       benno     985:                        close(*fileinfd);
                    986:                        *fileinfd = -1;
                    987:                        return -1;
                    988:                }
                    989:
1.24.2.1! benno     990:                if ((mbuf = malloc(blk.len)) == NULL) {
        !           991:                        ERR("malloc");
1.1       benno     992:                        close(*fileinfd);
                    993:                        *fileinfd = -1;
1.24.2.1! benno     994:                        free(blk.blks);
1.1       benno     995:                        return -1;
                    996:                }
                    997:
                    998:                offs = 0;
1.23      benno     999:                i = 0;
                   1000:                do {
                   1001:                        msz = pread(*fileinfd, mbuf, blk.len, offs);
1.24.2.1! benno    1002:                        if ((size_t)msz != blk.len && (size_t)msz != blk.rem) {
1.23      benno    1003:                                ERR("pread");
                   1004:                                close(*fileinfd);
                   1005:                                *fileinfd = -1;
1.24.2.1! benno    1006:                                free(mbuf);
        !          1007:                                free(blk.blks);
1.23      benno    1008:                                return -1;
                   1009:                        }
                   1010:                        init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess);
1.1       benno    1011:                        offs += blk.len;
1.23      benno    1012:                        LOG3(
                   1013:                            "i=%ld, offs=%lld, msz=%ld, blk.len=%lu, blk.rem=%lu",
                   1014:                            i, offs, msz, blk.len, blk.rem);
                   1015:                        i++;
                   1016:                } while (i < blk.blksz);
1.1       benno    1017:
1.24.2.1! benno    1018:                free(mbuf);
1.1       benno    1019:                close(*fileinfd);
                   1020:                *fileinfd = -1;
1.21      benno    1021:                LOG3("%s: mapped %jd B with %zu blocks",
1.19      deraadt  1022:                    u->fl[u->idx].path, (intmax_t)blk.size,
                   1023:                    blk.blksz);
1.1       benno    1024:        } else {
1.4       deraadt  1025:                if (*fileinfd != -1) {
1.1       benno    1026:                        close(*fileinfd);
                   1027:                        *fileinfd = -1;
                   1028:                }
                   1029:                blk.len = MAX_CHUNK; /* Doesn't matter. */
1.21      benno    1030:                LOG3("%s: not mapped", u->fl[u->idx].path);
1.1       benno    1031:        }
                   1032:
1.4       deraadt  1033:        assert(*fileinfd == -1);
1.1       benno    1034:
                   1035:        /* Make sure the block metadata buffer is big enough. */
                   1036:
1.2       benno    1037:        u->bufsz =
1.24.2.1! benno    1038:            sizeof(int32_t) + /* identifier */
        !          1039:            sizeof(int32_t) + /* block count */
        !          1040:            sizeof(int32_t) + /* block length */
        !          1041:            sizeof(int32_t) + /* checksum length */
        !          1042:            sizeof(int32_t) + /* block remainder */
        !          1043:            blk.blksz *
        !          1044:            (sizeof(int32_t) + /* short checksum */
        !          1045:            blk.csum); /* long checksum */
1.1       benno    1046:
                   1047:        if (u->bufsz > u->bufmax) {
1.4       deraadt  1048:                if ((bufp = realloc(u->buf, u->bufsz)) == NULL) {
1.21      benno    1049:                        ERR("realloc");
1.24.2.1! benno    1050:                        free(blk.blks);
1.1       benno    1051:                        return -1;
                   1052:                }
                   1053:                u->buf = bufp;
                   1054:                u->bufmax = u->bufsz;
                   1055:        }
                   1056:
                   1057:        u->bufpos = pos = 0;
1.22      benno    1058:        io_buffer_int(u->buf, &pos, u->bufsz, u->idx);
                   1059:        io_buffer_int(u->buf, &pos, u->bufsz, blk.blksz);
                   1060:        io_buffer_int(u->buf, &pos, u->bufsz, blk.len);
                   1061:        io_buffer_int(u->buf, &pos, u->bufsz, blk.csum);
                   1062:        io_buffer_int(u->buf, &pos, u->bufsz, blk.rem);
1.1       benno    1063:        for (i = 0; i < blk.blksz; i++) {
1.22      benno    1064:                io_buffer_int(u->buf, &pos, u->bufsz,
1.1       benno    1065:                        blk.blks[i].chksum_short);
1.22      benno    1066:                io_buffer_buf(u->buf, &pos, u->bufsz,
1.1       benno    1067:                        blk.blks[i].chksum_long, blk.csum);
                   1068:        }
                   1069:        assert(pos == u->bufsz);
                   1070:
                   1071:        /* Reenable the output poller and clean up. */
                   1072:
                   1073:        *fileoutfd = u->fdout;
                   1074:        free(blk.blks);
                   1075:        return 1;
                   1076: }
                   1077:
                   1078: /*
                   1079:  * Fix up the directory permissions and times post-order.
                   1080:  * We can't fix up directory permissions in place because the server may
                   1081:  * want us to have overly-tight permissions---say, those that don't
                   1082:  * allow writing into the directory.
                   1083:  * We also need to do our directory times post-order because making
                   1084:  * files within the directory will change modification times.
                   1085:  * Returns zero on failure, non-zero on success.
                   1086:  */
                   1087: int
                   1088: rsync_uploader_tail(struct upload *u, struct sess *sess)
                   1089: {
                   1090:        size_t   i;
                   1091:
                   1092:
1.3       deraadt  1093:        if (!sess->opts->preserve_times &&
1.20      deraadt  1094:            !sess->opts->preserve_perms)
1.1       benno    1095:                return 1;
                   1096:
1.21      benno    1097:        LOG2("fixing up directory times and permissions");
1.1       benno    1098:
                   1099:        for (i = 0; i < u->flsz; i++)
                   1100:                if (S_ISDIR(u->fl[i].st.mode))
1.3       deraadt  1101:                        if (!post_dir(sess, u, i))
1.1       benno    1102:                                return 0;
                   1103:
                   1104:        return 1;
                   1105: }