Annotation of src/usr.bin/rsync/uploader.c, Revision 1.30
1.30 ! claudio 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.30 ! claudio 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.30 ! claudio 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.30 ! claudio 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.30 ! claudio 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.30 ! claudio 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.30 ! claudio 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.30 ! claudio 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.30 ! claudio 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:
707: /*
708: * For non dry-run cases, we'll write the acknowledgement later
1.25 claudio 709: * in the rsync_uploader() function.
1.1 benno 710: */
711:
1.30 ! claudio 712: *size = 0;
1.26 claudio 713: *filefd = -1;
1.25 claudio 714:
1.30 ! claudio 715: rc = check_file(p->rootfd, f, &st);
! 716: if (rc == -1)
1.25 claudio 717: return -1;
1.30 ! claudio 718: if (rc == 2 && !S_ISREG(st.st_mode)) {
! 719: if (S_ISDIR(st.st_mode) &&
1.26 claudio 720: unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
721: ERR("%s: unlinkat", f->path);
722: return -1;
723: }
1.25 claudio 724: }
1.30 ! claudio 725: if (rc == 0) {
1.26 claudio 726: if (!rsync_set_metadata_at(sess, 0, p->rootfd, f, f->path)) {
1.25 claudio 727: ERRX1("rsync_set_metadata");
728: return -1;
729: }
1.30 ! claudio 730: LOG3("%s: skipping: up to date", f->path);
1.25 claudio 731: return 0;
732: }
733:
1.30 ! claudio 734: /* check alternative locations for better match */
! 735: for (i = 0; sess->opts->basedir[i] != NULL; i++) {
! 736: const char *root = sess->opts->basedir[i];
! 737: int dfd, x;
! 738:
! 739: dfd = openat(p->rootfd, root, O_RDONLY | O_DIRECTORY, 0);
! 740: if (dfd == -1)
! 741: err(ERR_FILE_IO, "%s: openat", root);
! 742: x = check_file(dfd, f, &st);
! 743: /* found a match */
! 744: if (x == 0) {
! 745: if (rc >= 0) {
! 746: /* found better match, delete file in rootfd */
! 747: if (unlinkat(p->rootfd, f->path, 0) == -1 &&
! 748: errno != ENOENT) {
! 749: ERR("%s: unlinkat", f->path);
! 750: return -1;
! 751: }
! 752: }
! 753: LOG3("%s: skipping: up to date in %s", f->path, root);
! 754: /* TODO: depending on mode link or copy file */
! 755: close(dfd);
! 756: return 0;
! 757: } else if (x == 1 && match == -1) {
! 758: /* found a local file that is a close match */
! 759: match = i;
! 760: }
! 761: close(dfd);
! 762: }
! 763: if (match != -1) {
! 764: /* copy match from basedir into root as a start point */
! 765: copy_file(p->rootfd, sess->opts->basedir[match], f);
! 766: if (fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) ==
! 767: -1) {
! 768: ERR("%s: fstatat", f->path);
! 769: return -1;
! 770: }
! 771: }
! 772:
! 773: *size = st.st_size;
1.26 claudio 774: *filefd = openat(p->rootfd, f->path, O_RDONLY | O_NOFOLLOW, 0);
775: if (*filefd == -1 && errno != ENOENT) {
776: ERR("%s: openat", f->path);
777: return -1;
778: }
779:
1.25 claudio 780: /* file needs attention */
781: return 1;
1.1 benno 782: }
783:
784: /*
785: * Allocate an uploader object in the correct state to start.
786: * Returns NULL on failure or the pointer otherwise.
787: * On success, upload_free() must be called with the allocated pointer.
788: */
789: struct upload *
1.22 benno 790: upload_alloc(const char *root, int rootfd, int fdout,
1.1 benno 791: size_t clen, const struct flist *fl, size_t flsz, mode_t msk)
792: {
793: struct upload *p;
794:
1.4 deraadt 795: if ((p = calloc(1, sizeof(struct upload))) == NULL) {
1.21 benno 796: ERR("calloc");
1.1 benno 797: return NULL;
798: }
799:
800: p->state = UPLOAD_FIND_NEXT;
801: p->oumask = msk;
1.11 florian 802: p->root = strdup(root);
803: if (p->root == NULL) {
1.21 benno 804: ERR("strdup");
1.11 florian 805: free(p);
806: return NULL;
807: }
1.1 benno 808: p->rootfd = rootfd;
809: p->csumlen = clen;
810: p->fdout = fdout;
811: p->fl = fl;
812: p->flsz = flsz;
813: p->newdir = calloc(flsz, sizeof(int));
1.4 deraadt 814: if (p->newdir == NULL) {
1.21 benno 815: ERR("calloc");
1.11 florian 816: free(p->root);
1.1 benno 817: free(p);
818: return NULL;
819: }
820: return p;
821: }
822:
823: /*
824: * Perform all cleanups and free.
825: * Passing a NULL to this function is ok.
826: */
827: void
828: upload_free(struct upload *p)
829: {
830:
1.4 deraadt 831: if (p == NULL)
1.1 benno 832: return;
1.11 florian 833: free(p->root);
1.1 benno 834: free(p->newdir);
835: free(p->buf);
836: free(p);
837: }
838:
839: /*
840: * Iterates through all available files and conditionally gets the file
841: * ready for processing to check whether it's up to date.
842: * If not up to date or empty, sends file information to the sender.
843: * If returns 0, we've processed all files there are to process.
844: * If returns >0, we're waiting for POLLIN or POLLOUT data.
845: * Otherwise returns <0, which is an error.
846: */
847: int
1.2 benno 848: rsync_uploader(struct upload *u, int *fileinfd,
1.1 benno 849: struct sess *sess, int *fileoutfd)
850: {
1.5 florian 851: struct blkset blk;
1.23 benno 852: void *mbuf, *bufp;
853: ssize_t msz;
854: size_t i, pos, sz;
1.30 ! claudio 855: off_t offs, filesize;
1.5 florian 856: int c;
1.1 benno 857:
1.26 claudio 858: /* Once finished this should never get called again. */
1.4 deraadt 859: assert(u->state != UPLOAD_FINISHED);
1.1 benno 860:
861: /*
862: * If we have an upload in progress, then keep writing until the
863: * buffer has been fully written.
864: * We must only have the output file descriptor working and also
865: * have a valid buffer to write.
866: */
867:
1.25 claudio 868: if (u->state == UPLOAD_WRITE) {
1.14 deraadt 869: assert(u->buf != NULL);
1.4 deraadt 870: assert(*fileoutfd != -1);
871: assert(*fileinfd == -1);
1.1 benno 872:
873: /*
874: * Unfortunately, we need to chunk these: if we're
875: * the server side of things, then we're multiplexing
876: * output and need to wrap this in chunks.
877: * This is a major deficiency of rsync.
878: * FIXME: add a "fast-path" mode that simply dumps out
879: * the buffer non-blocking if we're not mplexing.
880: */
881:
882: if (u->bufpos < u->bufsz) {
883: sz = MAX_CHUNK < (u->bufsz - u->bufpos) ?
884: MAX_CHUNK : (u->bufsz - u->bufpos);
1.2 benno 885: c = io_write_buf(sess, u->fdout,
1.1 benno 886: u->buf + u->bufpos, sz);
1.4 deraadt 887: if (c == 0) {
1.21 benno 888: ERRX1("io_write_nonblocking");
1.1 benno 889: return -1;
890: }
891: u->bufpos += sz;
892: if (u->bufpos < u->bufsz)
893: return 1;
894: }
895:
1.2 benno 896: /*
1.1 benno 897: * Let the UPLOAD_FIND_NEXT state handle things if we
898: * finish, as we'll need to write a POLLOUT message and
899: * not have a writable descriptor yet.
900: */
901:
902: u->state = UPLOAD_FIND_NEXT;
903: u->idx++;
904: return 1;
905: }
906:
907: /*
908: * If we invoke the uploader without a file currently open, then
909: * we iterate through til the next available regular file and
910: * start the opening process.
911: * This means we must have the output file descriptor working.
912: */
913:
1.4 deraadt 914: if (u->state == UPLOAD_FIND_NEXT) {
915: assert(*fileinfd == -1);
916: assert(*fileoutfd != -1);
1.1 benno 917:
918: for ( ; u->idx < u->flsz; u->idx++) {
919: if (S_ISDIR(u->fl[u->idx].st.mode))
920: c = pre_dir(u, sess);
921: else if (S_ISLNK(u->fl[u->idx].st.mode))
1.30 ! claudio 922: c = pre_symlink(u, sess);
1.1 benno 923: else if (S_ISREG(u->fl[u->idx].st.mode))
1.30 ! claudio 924: c = pre_file(u, fileinfd, &filesize, sess);
1.11 florian 925: else if (S_ISBLK(u->fl[u->idx].st.mode) ||
926: S_ISCHR(u->fl[u->idx].st.mode))
927: c = pre_dev(u, sess);
928: else if (S_ISFIFO(u->fl[u->idx].st.mode))
929: c = pre_fifo(u, sess);
930: else if (S_ISSOCK(u->fl[u->idx].st.mode))
931: c = pre_sock(u, sess);
1.1 benno 932: else
933: c = 0;
934:
935: if (c < 0)
936: return -1;
937: else if (c > 0)
938: break;
939: }
940:
1.2 benno 941: /*
1.1 benno 942: * Whether we've finished writing files or not, we
943: * disable polling on the output channel.
944: */
945:
946: *fileoutfd = -1;
947: if (u->idx == u->flsz) {
1.4 deraadt 948: assert(*fileinfd == -1);
1.3 deraadt 949: if (!io_write_int(sess, u->fdout, -1)) {
1.21 benno 950: ERRX1("io_write_int");
1.1 benno 951: return -1;
952: }
953: u->state = UPLOAD_FINISHED;
1.21 benno 954: LOG4("uploader: finished");
1.1 benno 955: return 0;
956: }
957:
958: /* Go back to the event loop, if necessary. */
959:
1.25 claudio 960: u->state = UPLOAD_WRITE;
1.1 benno 961: }
962:
963: /* Initialies our blocks. */
964:
1.25 claudio 965: assert(u->state == UPLOAD_WRITE);
1.1 benno 966: memset(&blk, 0, sizeof(struct blkset));
967: blk.csum = u->csumlen;
968:
1.30 ! claudio 969: if (*fileinfd != -1 && filesize > 0) {
! 970: init_blkset(&blk, filesize);
1.23 benno 971: assert(blk.blksz);
972:
973: blk.blks = calloc(blk.blksz, sizeof(struct blk));
974: if (blk.blks == NULL) {
975: ERR("calloc");
1.1 benno 976: close(*fileinfd);
977: *fileinfd = -1;
978: return -1;
979: }
980:
1.25 claudio 981: if ((mbuf = malloc(blk.len)) == NULL) {
982: ERR("malloc");
1.1 benno 983: close(*fileinfd);
984: *fileinfd = -1;
1.27 claudio 985: free(blk.blks);
1.1 benno 986: return -1;
987: }
988:
989: offs = 0;
1.23 benno 990: i = 0;
991: do {
992: msz = pread(*fileinfd, mbuf, blk.len, offs);
1.25 claudio 993: if ((size_t)msz != blk.len && (size_t)msz != blk.rem) {
1.23 benno 994: ERR("pread");
995: close(*fileinfd);
996: *fileinfd = -1;
1.25 claudio 997: free(mbuf);
1.27 claudio 998: free(blk.blks);
1.23 benno 999: return -1;
1000: }
1001: init_blk(&blk.blks[i], &blk, offs, i, mbuf, sess);
1.1 benno 1002: offs += blk.len;
1.23 benno 1003: LOG3(
1004: "i=%ld, offs=%lld, msz=%ld, blk.len=%lu, blk.rem=%lu",
1005: i, offs, msz, blk.len, blk.rem);
1006: i++;
1007: } while (i < blk.blksz);
1.1 benno 1008:
1.25 claudio 1009: free(mbuf);
1.1 benno 1010: close(*fileinfd);
1011: *fileinfd = -1;
1.21 benno 1012: LOG3("%s: mapped %jd B with %zu blocks",
1.19 deraadt 1013: u->fl[u->idx].path, (intmax_t)blk.size,
1014: blk.blksz);
1.1 benno 1015: } else {
1.4 deraadt 1016: if (*fileinfd != -1) {
1.1 benno 1017: close(*fileinfd);
1018: *fileinfd = -1;
1019: }
1020: blk.len = MAX_CHUNK; /* Doesn't matter. */
1.21 benno 1021: LOG3("%s: not mapped", u->fl[u->idx].path);
1.1 benno 1022: }
1023:
1.4 deraadt 1024: assert(*fileinfd == -1);
1.1 benno 1025:
1026: /* Make sure the block metadata buffer is big enough. */
1027:
1.2 benno 1028: u->bufsz =
1.1 benno 1029: sizeof(int32_t) + /* identifier */
1030: sizeof(int32_t) + /* block count */
1031: sizeof(int32_t) + /* block length */
1032: sizeof(int32_t) + /* checksum length */
1033: sizeof(int32_t) + /* block remainder */
1.2 benno 1034: blk.blksz *
1.1 benno 1035: (sizeof(int32_t) + /* short checksum */
1036: blk.csum); /* long checksum */
1037:
1038: if (u->bufsz > u->bufmax) {
1.4 deraadt 1039: if ((bufp = realloc(u->buf, u->bufsz)) == NULL) {
1.21 benno 1040: ERR("realloc");
1.27 claudio 1041: free(blk.blks);
1.1 benno 1042: return -1;
1043: }
1044: u->buf = bufp;
1045: u->bufmax = u->bufsz;
1046: }
1047:
1048: u->bufpos = pos = 0;
1.22 benno 1049: io_buffer_int(u->buf, &pos, u->bufsz, u->idx);
1050: io_buffer_int(u->buf, &pos, u->bufsz, blk.blksz);
1051: io_buffer_int(u->buf, &pos, u->bufsz, blk.len);
1052: io_buffer_int(u->buf, &pos, u->bufsz, blk.csum);
1053: io_buffer_int(u->buf, &pos, u->bufsz, blk.rem);
1.1 benno 1054: for (i = 0; i < blk.blksz; i++) {
1.22 benno 1055: io_buffer_int(u->buf, &pos, u->bufsz,
1.1 benno 1056: blk.blks[i].chksum_short);
1.22 benno 1057: io_buffer_buf(u->buf, &pos, u->bufsz,
1.1 benno 1058: blk.blks[i].chksum_long, blk.csum);
1059: }
1060: assert(pos == u->bufsz);
1061:
1062: /* Reenable the output poller and clean up. */
1063:
1064: *fileoutfd = u->fdout;
1065: free(blk.blks);
1066: return 1;
1067: }
1068:
1069: /*
1070: * Fix up the directory permissions and times post-order.
1071: * We can't fix up directory permissions in place because the server may
1072: * want us to have overly-tight permissions---say, those that don't
1073: * allow writing into the directory.
1074: * We also need to do our directory times post-order because making
1075: * files within the directory will change modification times.
1076: * Returns zero on failure, non-zero on success.
1077: */
1078: int
1079: rsync_uploader_tail(struct upload *u, struct sess *sess)
1080: {
1081: size_t i;
1082:
1083:
1.3 deraadt 1084: if (!sess->opts->preserve_times &&
1.20 deraadt 1085: !sess->opts->preserve_perms)
1.1 benno 1086: return 1;
1087:
1.21 benno 1088: LOG2("fixing up directory times and permissions");
1.1 benno 1089:
1090: for (i = 0; i < u->flsz; i++)
1091: if (S_ISDIR(u->fl[i].st.mode))
1.3 deraadt 1092: if (!post_dir(sess, u, i))
1.1 benno 1093: return 0;
1094:
1095: return 1;
1096: }