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

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;
1.2     ! benno      68:        }
1.1       benno      69:
1.2     ! benno      70:        /*
1.1       benno      71:         * Then the file list in any mode.
                     72:         * Finally, the IO error (always zero for us).
                     73:         */
1.2     ! benno      74:
1.1       benno      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;
1.2     ! benno      81:        }
1.1       benno      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: }