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