Annotation of src/usr.bin/rsync/uploader.c, Revision 1.4
1.4 ! deraadt 1: /* $Id: uploader.c,v 1.3 2019/02/11 19:18:36 deraadt Exp $ */
1.1 benno 2: /*
3: * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <sys/mman.h>
18: #include <sys/stat.h>
19:
20: #include <assert.h>
21: #include <errno.h>
22: #include <fcntl.h>
23: #include <inttypes.h>
24: #include <math.h>
25: #include <poll.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 */
36: UPLOAD_WRITE_LOCAL, /* wait to write to sender */
37: UPLOAD_READ_LOCAL, /* wait to read from local file */
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 */
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.2 benno 74: LOG1(sess, "%s%s", f->path,
1.1 benno 75: '/' == f->path[sz - 1] ? "" : "/");
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
83: log_link(struct sess *sess, const struct flist *f)
84: {
85:
1.3 deraadt 86: if (!sess->opts->server)
1.1 benno 87: LOG1(sess, "%s -> %s", f->path, f->link);
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.1 benno 98: LOG1(sess, "%s", f->path);
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.4 ! deraadt 153: assert(map != MAP_FAILED);
1.1 benno 154:
155: /* Block length inherits for all but the last. */
156:
157: p->idx = idx;
158: p->len = idx < set->blksz - 1 ? set->len : set->rem;
159: p->offs = offs;
160:
161: p->chksum_short = hash_fast(map + offs, p->len);
162: hash_slow(map + offs, p->len, p->chksum_long, sess);
163: }
164:
165: /*
166: * Return <0 on failure 0 on success.
167: */
168: static int
169: pre_link(struct upload *p, struct sess *sess)
170: {
171: int rc, newlink = 0;
172: char *b;
173: struct stat st;
174: struct timespec tv[2];
175: const struct flist *f;
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.1 benno 181: WARNX(sess, "%s: ignoring symlink", f->path);
182: return 0;
183: } else if (sess->opts->dry_run) {
184: log_link(sess, f);
185: return 0;
186: }
187:
188: /* See if the symlink already exists. */
189:
1.4 ! deraadt 190: assert(p->rootfd != -1);
1.1 benno 191: rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.4 ! deraadt 192: if (rc != -1 && !S_ISLNK(st.st_mode)) {
1.1 benno 193: WARNX(sess, "%s: not a symlink", f->path);
194: return -1;
1.4 ! deraadt 195: } else if (rc == -1 && errno != ENOENT) {
1.1 benno 196: WARN(sess, "%s: fstatat", f->path);
197: return -1;
198: }
199:
200: /*
201: * If the symbolic link already exists, then make sure that it
202: * points to the correct place.
203: * FIXME: does symlinkat() set permissions on the link using the
204: * destination file or the default umask?
205: * Do we need a fchmod in here as well?
206: */
207:
1.4 ! deraadt 208: if (rc == -1) {
1.1 benno 209: LOG3(sess, "%s: creating "
210: "symlink: %s", f->path, f->link);
1.4 ! deraadt 211: if (symlinkat(f->link, p->rootfd, f->path) == -1) {
1.1 benno 212: WARN(sess, "%s: symlinkat", f->path);
213: return -1;
214: }
215: newlink = 1;
216: } else {
217: b = symlinkat_read(sess, p->rootfd, f->path);
1.4 ! deraadt 218: if (b == NULL) {
1.1 benno 219: ERRX1(sess, "%s: symlinkat_read", f->path);
220: return -1;
221: }
222: if (strcmp(f->link, b)) {
223: free(b);
224: b = NULL;
225: LOG3(sess, "%s: updating "
226: "symlink: %s", f->path, f->link);
1.4 ! deraadt 227: if (unlinkat(p->rootfd, f->path, 0) == -1) {
1.1 benno 228: WARN(sess, "%s: unlinkat", f->path);
229: return -1;
230: }
1.4 ! deraadt 231: if (symlinkat(f->link, p->rootfd, f->path) == -1) {
1.1 benno 232: WARN(sess, "%s: symlinkat", f->path);
233: return -1;
234: }
235: newlink = 1;
1.2 benno 236: }
1.1 benno 237: free(b);
238: }
239:
240: /* Optionally preserve times/perms on the symlink. */
241:
242: if (sess->opts->preserve_times) {
243: tv[0].tv_sec = time(NULL);
244: tv[0].tv_nsec = 0;
245: tv[1].tv_sec = f->st.mtime;
246: tv[1].tv_nsec = 0;
1.2 benno 247: rc = utimensat(p->rootfd,
1.1 benno 248: f->path, tv, AT_SYMLINK_NOFOLLOW);
1.4 ! deraadt 249: if (rc == -1) {
1.1 benno 250: ERR(sess, "%s: utimensat", f->path);
251: return -1;
252: }
253: LOG4(sess, "%s: updated symlink date", f->path);
254: }
1.2 benno 255:
256: /*
1.1 benno 257: * FIXME: if newlink is set because we updated the symlink, we
258: * want to carry over the permissions from the last.
259: */
260:
261: if (newlink || sess->opts->preserve_perms) {
1.4 ! deraadt 262: rc = fchmodat(p->rootfd,
! 263: f->path, f->st.mode, AT_SYMLINK_NOFOLLOW);
! 264: if (rc == -1) {
1.1 benno 265: ERR(sess, "%s: fchmodat", f->path);
266: return -1;
267: }
268: LOG4(sess, "%s: updated symlink mode", f->path);
269: }
270:
271: log_link(sess, f);
272: return 0;
273: }
274:
275: /*
276: * If not found, create the destination directory in prefix order.
277: * Create directories using the existing umask.
278: * Return <0 on failure 0 on success.
279: */
280: static int
281: pre_dir(const struct upload *p, struct sess *sess)
282: {
283: struct stat st;
1.2 benno 284: int rc;
1.1 benno 285: const struct flist *f;
286:
287: f = &p->fl[p->idx];
288: assert(S_ISDIR(f->st.mode));
289:
1.3 deraadt 290: if (!sess->opts->recursive) {
1.1 benno 291: WARNX(sess, "%s: ignoring directory", f->path);
292: return 0;
293: } else if (sess->opts->dry_run) {
294: log_dir(sess, f);
295: return 0;
296: }
297:
1.4 ! deraadt 298: assert(p->rootfd != -1);
1.1 benno 299: rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.4 ! deraadt 300: if (rc == -1 && errno != ENOENT) {
1.1 benno 301: WARN(sess, "%s: fstatat", f->path);
302: return -1;
1.4 ! deraadt 303: } else if (rc != -1 && !S_ISDIR(st.st_mode)) {
1.1 benno 304: WARNX(sess, "%s: not a directory", f->path);
305: return -1;
1.4 ! deraadt 306: } else if (rc != -1) {
1.2 benno 307: /*
1.1 benno 308: * FIXME: we should fchmod the permissions here as well,
309: * as we may locally have shut down writing into the
310: * directory and that doesn't work.
311: */
312: LOG3(sess, "%s: updating directory", f->path);
313: return 0;
314: }
315:
316: /*
317: * We want to make the directory with default permissions (using
318: * our old umask, which we've since unset), then adjust
319: * permissions (assuming preserve_perms or new) afterward in
320: * case it's u-w or something.
321: */
322:
323: LOG3(sess, "%s: creating directory", f->path);
1.4 ! deraadt 324: if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) {
1.1 benno 325: WARN(sess, "%s: mkdirat", f->path);
326: return -1;
327: }
328:
329: p->newdir[p->idx] = 1;
330: log_dir(sess, f);
331: return 0;
332: }
333:
334: /*
335: * Process the directory time and mode for "idx" in the file list.
336: * Returns zero on failure, non-zero on success.
337: */
338: static int
339: post_dir(struct sess *sess, const struct upload *u, size_t idx)
340: {
341: struct timespec tv[2];
342: int rc;
343: struct stat st;
344: const struct flist *f;
345:
346: f = &u->fl[idx];
347: assert(S_ISDIR(f->st.mode));
348:
349: /* We already warned about the directory in pre_process_dir(). */
350:
1.3 deraadt 351: if (!sess->opts->recursive)
1.1 benno 352: return 1;
353: else if (sess->opts->dry_run)
354: return 1;
355:
1.4 ! deraadt 356: if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
1.1 benno 357: ERR(sess, "%s: fstatat", f->path);
358: return 0;
1.3 deraadt 359: } else if (!S_ISDIR(st.st_mode)) {
1.1 benno 360: WARNX(sess, "%s: not a directory", f->path);
361: return 0;
362: }
363:
1.2 benno 364: /*
1.1 benno 365: * Update the modification time if we're a new directory *or* if
366: * we're preserving times and the time has changed.
367: */
368:
1.2 benno 369: if (u->newdir[idx] ||
370: (sess->opts->preserve_times &&
1.1 benno 371: st.st_mtime != f->st.mtime)) {
372: tv[0].tv_sec = time(NULL);
373: tv[0].tv_nsec = 0;
374: tv[1].tv_sec = f->st.mtime;
375: tv[1].tv_nsec = 0;
376: rc = utimensat(u->rootfd, f->path, tv, 0);
1.4 ! deraadt 377: if (rc == -1) {
1.1 benno 378: ERR(sess, "%s: utimensat", f->path);
379: return 0;
380: }
381: LOG4(sess, "%s: updated date", f->path);
382: }
383:
384: /*
385: * Update the mode if we're a new directory *or* if we're
386: * preserving modes and it has changed.
387: */
388:
1.2 benno 389: if (u->newdir[idx] ||
1.1 benno 390: (sess->opts->preserve_perms &&
391: st.st_mode != f->st.mode)) {
392: rc = fchmodat(u->rootfd, f->path, f->st.mode, 0);
1.4 ! deraadt 393: if (rc == -1) {
1.1 benno 394: ERR(sess, "%s: fchmodat", f->path);
395: return 0;
396: }
397: LOG4(sess, "%s: updated mode", f->path);
398: }
399:
400: return 1;
401: }
402:
403: /*
404: * Try to open the file at the current index.
405: * If the file does not exist, returns with success.
406: * Return <0 on failure, 0 on success w/nothing to be done, >0 on
407: * success and the file needs attention.
408: */
409: static int
410: pre_file(const struct upload *p, int *filefd, struct sess *sess)
411: {
412: const struct flist *f;
413:
414: f = &p->fl[p->idx];
415: assert(S_ISREG(f->st.mode));
416:
417: if (sess->opts->dry_run) {
418: log_file(sess, f);
1.3 deraadt 419: if (!io_write_int(sess, p->fdout, p->idx)) {
1.1 benno 420: ERRX1(sess, "io_write_int");
421: return -1;
422: }
423: return 0;
424: }
425:
426: /*
427: * For non dry-run cases, we'll write the acknowledgement later
428: * in the rsync_uploader() function because we need to wait for
429: * the open() call to complete.
430: * If the call to openat() fails with ENOENT, there's a
431: * fast-path between here and the write function, so we won't do
432: * any blocking between now and then.
433: */
434:
435: *filefd = openat(p->rootfd, f->path,
436: O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0);
1.4 ! deraadt 437: if (*filefd != -1 || errno == ENOENT)
1.1 benno 438: return 1;
439: ERR(sess, "%s: openat", f->path);
440: return -1;
441: }
442:
443: /*
444: * Allocate an uploader object in the correct state to start.
445: * Returns NULL on failure or the pointer otherwise.
446: * On success, upload_free() must be called with the allocated pointer.
447: */
448: struct upload *
1.2 benno 449: upload_alloc(struct sess *sess, int rootfd, int fdout,
1.1 benno 450: size_t clen, const struct flist *fl, size_t flsz, mode_t msk)
451: {
452: struct upload *p;
453:
1.4 ! deraadt 454: if ((p = calloc(1, sizeof(struct upload))) == NULL) {
1.1 benno 455: ERR(sess, "calloc");
456: return NULL;
457: }
458:
459: p->state = UPLOAD_FIND_NEXT;
460: p->oumask = msk;
461: p->rootfd = rootfd;
462: p->csumlen = clen;
463: p->fdout = fdout;
464: p->fl = fl;
465: p->flsz = flsz;
466: p->newdir = calloc(flsz, sizeof(int));
1.4 ! deraadt 467: if (p->newdir == NULL) {
1.1 benno 468: ERR(sess, "calloc");
469: free(p);
470: return NULL;
471: }
472: return p;
473: }
474:
475: /*
476: * Perform all cleanups and free.
477: * Passing a NULL to this function is ok.
478: */
479: void
480: upload_free(struct upload *p)
481: {
482:
1.4 ! deraadt 483: if (p == NULL)
1.1 benno 484: return;
485: free(p->newdir);
486: free(p->buf);
487: free(p);
488: }
489:
490: /*
491: * Iterates through all available files and conditionally gets the file
492: * ready for processing to check whether it's up to date.
493: * If not up to date or empty, sends file information to the sender.
494: * If returns 0, we've processed all files there are to process.
495: * If returns >0, we're waiting for POLLIN or POLLOUT data.
496: * Otherwise returns <0, which is an error.
497: */
498: int
1.2 benno 499: rsync_uploader(struct upload *u, int *fileinfd,
1.1 benno 500: struct sess *sess, int *fileoutfd)
501: {
502: struct blkset blk;
503: struct stat st;
504: void *map, *bufp;
505: size_t i, mapsz, pos, sz;
506: off_t offs;
507: int c;
508:
509: /* This should never get called. */
510:
1.4 ! deraadt 511: assert(u->state != UPLOAD_FINISHED);
1.1 benno 512:
513: /*
514: * If we have an upload in progress, then keep writing until the
515: * buffer has been fully written.
516: * We must only have the output file descriptor working and also
517: * have a valid buffer to write.
518: */
519:
1.4 ! deraadt 520: if (u->state == UPLOAD_WRITE_LOCAL) {
1.1 benno 521: assert(NULL != u->buf);
1.4 ! deraadt 522: assert(*fileoutfd != -1);
! 523: assert(*fileinfd == -1);
1.1 benno 524:
525: /*
526: * Unfortunately, we need to chunk these: if we're
527: * the server side of things, then we're multiplexing
528: * output and need to wrap this in chunks.
529: * This is a major deficiency of rsync.
530: * FIXME: add a "fast-path" mode that simply dumps out
531: * the buffer non-blocking if we're not mplexing.
532: */
533:
534: if (u->bufpos < u->bufsz) {
535: sz = MAX_CHUNK < (u->bufsz - u->bufpos) ?
536: MAX_CHUNK : (u->bufsz - u->bufpos);
1.2 benno 537: c = io_write_buf(sess, u->fdout,
1.1 benno 538: u->buf + u->bufpos, sz);
1.4 ! deraadt 539: if (c == 0) {
1.1 benno 540: ERRX1(sess, "io_write_nonblocking");
541: return -1;
542: }
543: u->bufpos += sz;
544: if (u->bufpos < u->bufsz)
545: return 1;
546: }
547:
1.2 benno 548: /*
1.1 benno 549: * Let the UPLOAD_FIND_NEXT state handle things if we
550: * finish, as we'll need to write a POLLOUT message and
551: * not have a writable descriptor yet.
552: */
553:
554: u->state = UPLOAD_FIND_NEXT;
555: u->idx++;
556: return 1;
557: }
558:
559: /*
560: * If we invoke the uploader without a file currently open, then
561: * we iterate through til the next available regular file and
562: * start the opening process.
563: * This means we must have the output file descriptor working.
564: */
565:
1.4 ! deraadt 566: if (u->state == UPLOAD_FIND_NEXT) {
! 567: assert(*fileinfd == -1);
! 568: assert(*fileoutfd != -1);
1.1 benno 569:
570: for ( ; u->idx < u->flsz; u->idx++) {
571: if (S_ISDIR(u->fl[u->idx].st.mode))
572: c = pre_dir(u, sess);
573: else if (S_ISLNK(u->fl[u->idx].st.mode))
574: c = pre_link(u, sess);
575: else if (S_ISREG(u->fl[u->idx].st.mode))
576: c = pre_file(u, fileinfd, sess);
577: else
578: c = 0;
579:
580: if (c < 0)
581: return -1;
582: else if (c > 0)
583: break;
584: }
585:
1.2 benno 586: /*
1.1 benno 587: * Whether we've finished writing files or not, we
588: * disable polling on the output channel.
589: */
590:
591: *fileoutfd = -1;
592: if (u->idx == u->flsz) {
1.4 ! deraadt 593: assert(*fileinfd == -1);
1.3 deraadt 594: if (!io_write_int(sess, u->fdout, -1)) {
1.1 benno 595: ERRX1(sess, "io_write_int");
596: return -1;
597: }
598: u->state = UPLOAD_FINISHED;
599: LOG4(sess, "uploader: finished");
600: return 0;
601: }
602:
603: /* Go back to the event loop, if necessary. */
604:
605: u->state = -1 == *fileinfd ?
606: UPLOAD_WRITE_LOCAL : UPLOAD_READ_LOCAL;
1.4 ! deraadt 607: if (u->state == UPLOAD_READ_LOCAL)
1.1 benno 608: return 1;
609: }
610:
1.2 benno 611: /*
1.1 benno 612: * If an input file is open, stat it and see if it's already up
613: * to date, in which case close it and go to the next one.
614: * Either way, we don't have a write channel open.
615: */
616:
1.4 ! deraadt 617: if (u->state == UPLOAD_READ_LOCAL) {
! 618: assert(*fileinfd != -1);
! 619: assert(*fileoutfd == -1);
1.1 benno 620:
1.4 ! deraadt 621: if (fstat(*fileinfd, &st) == -1) {
1.1 benno 622: WARN(sess, "%s: fstat", u->fl[u->idx].path);
623: close(*fileinfd);
624: *fileinfd = -1;
625: return -1;
1.3 deraadt 626: } else if (!S_ISREG(st.st_mode)) {
1.1 benno 627: WARNX(sess, "%s: not regular", u->fl[u->idx].path);
628: close(*fileinfd);
629: *fileinfd = -1;
630: return -1;
631: }
632:
633: if (st.st_size == u->fl[u->idx].st.size &&
634: st.st_mtime == u->fl[u->idx].st.mtime) {
635: LOG3(sess, "%s: skipping: "
636: "up to date", u->fl[u->idx].path);
637: close(*fileinfd);
638: *fileinfd = -1;
639: *fileoutfd = u->fdout;
640: u->state = UPLOAD_FIND_NEXT;
641: u->idx++;
642: return 1;
643: }
644:
645: /* Fallthrough... */
646:
647: u->state = UPLOAD_WRITE_LOCAL;
648: }
649:
650: /* Initialies our blocks. */
651:
1.4 ! deraadt 652: assert(u->state == UPLOAD_WRITE_LOCAL);
1.1 benno 653: memset(&blk, 0, sizeof(struct blkset));
654: blk.csum = u->csumlen;
655:
1.4 ! deraadt 656: if (*fileinfd != -1 && st.st_size > 0) {
1.1 benno 657: mapsz = st.st_size;
1.2 benno 658: map = mmap(NULL, mapsz,
1.1 benno 659: PROT_READ, MAP_SHARED, *fileinfd, 0);
1.4 ! deraadt 660: if (map == MAP_FAILED) {
1.1 benno 661: WARN(sess, "%s: mmap", u->fl[u->idx].path);
662: close(*fileinfd);
663: *fileinfd = -1;
664: return -1;
665: }
666:
667: init_blkset(&blk, st.st_size);
668: assert(blk.blksz);
669:
670: blk.blks = calloc(blk.blksz, sizeof(struct blk));
1.4 ! deraadt 671: if (blk.blks == NULL) {
1.1 benno 672: ERR(sess, "calloc");
673: munmap(map, mapsz);
674: close(*fileinfd);
675: *fileinfd = -1;
676: return -1;
677: }
678:
679: offs = 0;
680: for (i = 0; i < blk.blksz; i++) {
1.2 benno 681: init_blk(&blk.blks[i],
1.1 benno 682: &blk, offs, i, map, sess);
683: offs += blk.len;
684: }
685:
686: munmap(map, mapsz);
687: close(*fileinfd);
688: *fileinfd = -1;
689: LOG3(sess, "%s: mapped %jd B with %zu blocks",
1.2 benno 690: u->fl[u->idx].path, (intmax_t)blk.size,
1.1 benno 691: blk.blksz);
692: } else {
1.4 ! deraadt 693: if (*fileinfd != -1) {
1.1 benno 694: close(*fileinfd);
695: *fileinfd = -1;
696: }
697: blk.len = MAX_CHUNK; /* Doesn't matter. */
698: LOG3(sess, "%s: not mapped", u->fl[u->idx].path);
699: }
700:
1.4 ! deraadt 701: assert(*fileinfd == -1);
1.1 benno 702:
703: /* Make sure the block metadata buffer is big enough. */
704:
1.2 benno 705: u->bufsz =
1.1 benno 706: sizeof(int32_t) + /* identifier */
707: sizeof(int32_t) + /* block count */
708: sizeof(int32_t) + /* block length */
709: sizeof(int32_t) + /* checksum length */
710: sizeof(int32_t) + /* block remainder */
1.2 benno 711: blk.blksz *
1.1 benno 712: (sizeof(int32_t) + /* short checksum */
713: blk.csum); /* long checksum */
714:
715: if (u->bufsz > u->bufmax) {
1.4 ! deraadt 716: if ((bufp = realloc(u->buf, u->bufsz)) == NULL) {
1.1 benno 717: ERR(sess, "realloc");
718: return -1;
719: }
720: u->buf = bufp;
721: u->bufmax = u->bufsz;
722: }
723:
724: u->bufpos = pos = 0;
725: io_buffer_int(sess, u->buf, &pos, u->bufsz, u->idx);
726: io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.blksz);
727: io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.len);
728: io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.csum);
729: io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.rem);
730: for (i = 0; i < blk.blksz; i++) {
1.2 benno 731: io_buffer_int(sess, u->buf, &pos, u->bufsz,
1.1 benno 732: blk.blks[i].chksum_short);
1.2 benno 733: io_buffer_buf(sess, u->buf, &pos, u->bufsz,
1.1 benno 734: blk.blks[i].chksum_long, blk.csum);
735: }
736: assert(pos == u->bufsz);
737:
738: /* Reenable the output poller and clean up. */
739:
740: *fileoutfd = u->fdout;
741: free(blk.blks);
742: return 1;
743: }
744:
745: /*
746: * Fix up the directory permissions and times post-order.
747: * We can't fix up directory permissions in place because the server may
748: * want us to have overly-tight permissions---say, those that don't
749: * allow writing into the directory.
750: * We also need to do our directory times post-order because making
751: * files within the directory will change modification times.
752: * Returns zero on failure, non-zero on success.
753: */
754: int
755: rsync_uploader_tail(struct upload *u, struct sess *sess)
756: {
757: size_t i;
758:
759:
1.3 deraadt 760: if (!sess->opts->preserve_times &&
761: !sess->opts->preserve_perms)
1.1 benno 762: return 1;
763:
764: LOG2(sess, "fixing up directory times and permissions");
765:
766: for (i = 0; i < u->flsz; i++)
767: if (S_ISDIR(u->fl[i].st.mode))
1.3 deraadt 768: if (!post_dir(sess, u, i))
1.1 benno 769: return 0;
770:
771: return 1;
772: }