Annotation of src/usr.bin/rsync/uploader.c, Revision 1.29.2.1
1.29.2.1! benno 1: /* $OpenBSD: uploader.c,v 1.29 2021/06/30 13:10: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.29.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.25 claudio 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.26 claudio 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.29.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.25 claudio 183: }
184: if (sess->opts->dry_run) {
1.26 claudio 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.28 claudio 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.26 claudio 265: log_symlink(sess, f);
1.11 florian 266: return 0;
267: }
268:
269: /*
1.29.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.25 claudio 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.28 claudio 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.29.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.25 claudio 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.28 claudio 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.29.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.25 claudio 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.28 claudio 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.25 claudio 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.28 claudio 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.25 claudio 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.25 claudio 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.29.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.25 claudio 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.29.2.1! benno 688: pre_file(const struct upload *p, int *filefd, off_t *size,
1.25 claudio 689: struct sess *sess)
1.1 benno 690: {
691: const struct flist *f;
1.29.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.29.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.25 claudio 718: * in the rsync_uploader() function.
1.1 benno 719: */
720:
1.29.2.1! benno 721: *size = 0;
1.26 claudio 722: *filefd = -1;
723:
1.29.2.1! benno 724: rc = check_file(p->rootfd, f, &st);
! 725: if (rc == -1)
1.25 claudio 726: return -1;
1.29.2.1! benno 727: if (rc == 2 && !S_ISREG(st.st_mode)) {
! 728: if (S_ISDIR(st.st_mode) &&
1.26 claudio 729: unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
730: ERR("%s: unlinkat", f->path);
731: return -1;
732: }
1.25 claudio 733: }
1.29.2.1! benno 734: if (rc == 0) {
1.26 claudio 735: if (!rsync_set_metadata_at(sess, 0, p->rootfd, f, f->path)) {
1.25 claudio 736: ERRX1("rsync_set_metadata");
737: return -1;
738: }
1.29.2.1! benno 739: LOG3("%s: skipping: up to date", f->path);
1.25 claudio 740: return 0;
741: }
742:
1.29.2.1! benno 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);
1.26 claudio 784: if (*filefd == -1 && errno != ENOENT) {
785: ERR("%s: openat", f->path);
786: return -1;
787: }
788:
1.25 claudio 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.29.2.1! benno 864: off_t offs, filesize;
1.5 florian 865: int c;
1.1 benno 866:
1.26 claudio 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.25 claudio 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.29.2.1! benno 931: c = pre_symlink(u, sess);
1.1 benno 932: else if (S_ISREG(u->fl[u->idx].st.mode))
1.29.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.25 claudio 969: u->state = UPLOAD_WRITE;
1.1 benno 970: }
971:
972: /* Initialies our blocks. */
973:
1.25 claudio 974: assert(u->state == UPLOAD_WRITE);
1.1 benno 975: memset(&blk, 0, sizeof(struct blkset));
976: blk.csum = u->csumlen;
977:
1.29.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.25 claudio 990: if ((mbuf = malloc(blk.len)) == NULL) {
991: ERR("malloc");
1.1 benno 992: close(*fileinfd);
993: *fileinfd = -1;
1.27 claudio 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.25 claudio 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.25 claudio 1006: free(mbuf);
1.27 claudio 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.25 claudio 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.29.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.27 claudio 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: }