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