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

Annotation of src/usr.bin/rsync/sender.c, Revision 1.1

1.1     ! benno       1: /*     $Id$ */
        !             2: /*
        !             3:  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17: #include <sys/stat.h>
        !            18:
        !            19: #include <assert.h>
        !            20: #include <inttypes.h>
        !            21: #include <stdlib.h>
        !            22: #include <string.h>
        !            23: #include <unistd.h>
        !            24:
        !            25: #include "extern.h"
        !            26:
        !            27: /*
        !            28:  * A client sender manages the read-only source files and sends data to
        !            29:  * the receiver as requested.
        !            30:  * First it sends its list of files, then it waits for the server to
        !            31:  * request updates to individual files.
        !            32:  * Returns zero on failure, non-zero on success.
        !            33:  *
        !            34:  * Pledges: stdio, rpath, unveil.
        !            35:  */
        !            36: int
        !            37: rsync_sender(struct sess *sess, int fdin,
        !            38:        int fdout, size_t argc, char **argv)
        !            39: {
        !            40:        struct flist    *fl = NULL;
        !            41:        size_t           flsz = 0, phase = 0, excl;
        !            42:        int              rc = 0, c;
        !            43:        int32_t          idx;
        !            44:        struct blkset   *blks = NULL;
        !            45:
        !            46:        if (-1 == pledge("unveil stdio rpath", NULL)) {
        !            47:                ERR(sess, "pledge");
        !            48:                return 0;
        !            49:        }
        !            50:
        !            51:        /*
        !            52:         * Generate the list of files we want to send from our
        !            53:         * command-line input.
        !            54:         * This will also remove all invalid files.
        !            55:         */
        !            56:
        !            57:        if ( ! flist_gen(sess, argc, argv, &fl, &flsz)) {
        !            58:                ERRX1(sess, "flist_gen");
        !            59:                goto out;
        !            60:        }
        !            61:
        !            62:        /* Client sends zero-length exclusions if deleting. */
        !            63:
        !            64:        if ( ! sess->opts->server && sess->opts->del &&
        !            65:             ! io_write_int(sess, fdout, 0)) {
        !            66:                ERRX1(sess, "io_write_int");
        !            67:                goto out;
        !            68:        }
        !            69:
        !            70:        /*
        !            71:         * Then the file list in any mode.
        !            72:         * Finally, the IO error (always zero for us).
        !            73:         */
        !            74:
        !            75:        if ( ! flist_send(sess, fdin, fdout, fl, flsz)) {
        !            76:                ERRX1(sess, "flist_send");
        !            77:                goto out;
        !            78:        } else if ( ! io_write_int(sess, fdout, 0)) {
        !            79:                ERRX1(sess, "io_write_int");
        !            80:                goto out;
        !            81:        }
        !            82:
        !            83:        /* Exit if we're the server with zero files. */
        !            84:
        !            85:        if (0 == flsz && sess->opts->server) {
        !            86:                WARNX(sess, "sender has empty file list: exiting");
        !            87:                rc = 1;
        !            88:                goto out;
        !            89:        } else if ( ! sess->opts->server)
        !            90:                LOG1(sess, "Transfer starting: %zu files", flsz);
        !            91:
        !            92:        /*
        !            93:         * If we're the server, read our exclusion list.
        !            94:         * This is always 0 for now.
        !            95:         */
        !            96:
        !            97:        if (sess->opts->server) {
        !            98:                if ( ! io_read_size(sess, fdin, &excl)) {
        !            99:                        ERRX1(sess, "io_read_size");
        !           100:                        goto out;
        !           101:                } else if (0 != excl) {
        !           102:                        ERRX1(sess, "exclusion list is non-empty");
        !           103:                        goto out;
        !           104:                }
        !           105:        }
        !           106:
        !           107:        /*
        !           108:         * We have two phases: the first has a two-byte checksum, the
        !           109:         * second has a full 16-byte checksum.
        !           110:         */
        !           111:
        !           112:        LOG2(sess, "sender transmitting phase 1 data");
        !           113:
        !           114:        for (;;) {
        !           115:                if ( ! io_read_int(sess, fdin, &idx)) {
        !           116:                        ERRX1(sess, "io_read_int");
        !           117:                        goto out;
        !           118:                }
        !           119:
        !           120:                /*
        !           121:                 * If we receive an invalid index (-1), then we're
        !           122:                 * either promoted to the second phase or it's time to
        !           123:                 * exit, depending upon which phase we're in.
        !           124:                 */
        !           125:
        !           126:                if (-1 == idx) {
        !           127:                        if ( ! io_write_int(sess, fdout, idx)) {
        !           128:                                ERRX1(sess, "io_write_int");
        !           129:                                goto out;
        !           130:                        }
        !           131:
        !           132:                        /* FIXME: I don't understand this ack. */
        !           133:
        !           134:                        if (sess->opts->server && sess->rver > 27)
        !           135:                                if ( ! io_write_int(sess, fdout, idx)) {
        !           136:                                        ERRX1(sess, "io_write_int");
        !           137:                                        goto out;
        !           138:                                }
        !           139:
        !           140:                        if (phase++)
        !           141:                                break;
        !           142:                        LOG2(sess, "sender transmitting phase 2 data");
        !           143:                        continue;
        !           144:                }
        !           145:
        !           146:                /* Validate index and file type. */
        !           147:
        !           148:                if (idx < 0 || (uint32_t)idx >= flsz) {
        !           149:                        ERRX(sess, "file index out of bounds: "
        !           150:                                "invalid %" PRId32 " out of %zu",
        !           151:                                idx, flsz);
        !           152:                        goto out;
        !           153:                } else if (S_ISDIR(fl[idx].st.mode)) {
        !           154:                        ERRX(sess, "blocks requested for "
        !           155:                                "directory: %s", fl[idx].path);
        !           156:                        goto out;
        !           157:                } else if (S_ISLNK(fl[idx].st.mode)) {
        !           158:                        ERRX(sess, "blocks requested for "
        !           159:                                "symlink: %s", fl[idx].path);
        !           160:                        goto out;
        !           161:                } else if ( ! S_ISREG(fl[idx].st.mode)) {
        !           162:                        ERRX(sess, "blocks requested for "
        !           163:                                "special: %s", fl[idx].path);
        !           164:                        goto out;
        !           165:                }
        !           166:
        !           167:                if ( ! sess->opts->server)
        !           168:                        LOG1(sess, "%s", fl[idx].wpath);
        !           169:
        !           170:                /* Dry-run doesn't do anything. */
        !           171:
        !           172:                if (sess->opts->dry_run) {
        !           173:                        if ( ! io_write_int(sess, fdout, idx)) {
        !           174:                                ERRX1(sess, "io_write_int");
        !           175:                                goto out;
        !           176:                        }
        !           177:                        continue;
        !           178:                }
        !           179:
        !           180:                /*
        !           181:                 * The server will now send us its view of the file.
        !           182:                 * It does so by cutting a file into a series of blocks
        !           183:                 * and checksumming each block.
        !           184:                 * We can then compare the blocks in our file and those
        !           185:                 * in theirs, and send them blocks they're missing or
        !           186:                 * don't have.
        !           187:                 */
        !           188:
        !           189:                blks = blk_recv(sess, fdin, fl[idx].path);
        !           190:                if (NULL == blks) {
        !           191:                        ERRX1(sess, "blk_recv");
        !           192:                        goto out;
        !           193:                } else if ( ! blk_recv_ack(sess, fdout, blks, idx)) {
        !           194:                        ERRX1(sess, "blk_recv_ack");
        !           195:                        goto out;
        !           196:                }
        !           197:
        !           198:                c = blk_match(sess, fdout, blks, fl[idx].path);
        !           199:                blkset_free(blks);
        !           200:
        !           201:                if ( ! c) {
        !           202:                        ERRX1(sess, "blk_match");
        !           203:                        goto out;
        !           204:                }
        !           205:        }
        !           206:
        !           207:        if ( ! sess_stats_send(sess, fdout)) {
        !           208:                ERRX1(sess, "sess_stats_end");
        !           209:                goto out;
        !           210:        }
        !           211:
        !           212:        /* Final "goodbye" message. */
        !           213:
        !           214:        if ( ! io_read_int(sess, fdin, &idx)) {
        !           215:                ERRX1(sess, "io_read_int");
        !           216:                goto out;
        !           217:        } else if (-1 != idx) {
        !           218:                ERRX(sess, "read incorrect update complete ack");
        !           219:                goto out;
        !           220:        }
        !           221:
        !           222:        LOG2(sess, "sender finished updating");
        !           223:        rc = 1;
        !           224: out:
        !           225:        flist_free(fl, flsz);
        !           226:        return rc;
        !           227: }