xref: /openbsd-src/usr.bin/rsync/uploader.c (revision 9f11ffb7133c203312a01e4b986886bc88c7d74b)
1 /*	$Id: uploader.c,v 1.4 2019/02/11 21:41:22 deraadt Exp $ */
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);
74 	LOG1(sess, "%s%s", f->path,
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 
86 	if (!sess->opts->server)
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 
97 	if (!sess->opts->server)
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 
122 		/*
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;
133 	if ((p->blksz = sz / p->len) == 0)
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 
153 	assert(map != MAP_FAILED);
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 
180 	if (!sess->opts->preserve_links) {
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 
190 	assert(p->rootfd != -1);
191 	rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
192 	if (rc != -1 && !S_ISLNK(st.st_mode)) {
193 		WARNX(sess, "%s: not a symlink", f->path);
194 		return -1;
195 	} else if (rc == -1 && errno != ENOENT) {
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 
208 	if (rc == -1) {
209 		LOG3(sess, "%s: creating "
210 			"symlink: %s", f->path, f->link);
211 		if (symlinkat(f->link, p->rootfd, f->path) == -1) {
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);
218 		if (b == NULL) {
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);
227 			if (unlinkat(p->rootfd, f->path, 0) == -1) {
228 				WARN(sess, "%s: unlinkat", f->path);
229 				return -1;
230 			}
231 			if (symlinkat(f->link, p->rootfd, f->path) == -1) {
232 				WARN(sess, "%s: symlinkat", f->path);
233 				return -1;
234 			}
235 			newlink = 1;
236 		}
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;
247 		rc = utimensat(p->rootfd,
248 			f->path, tv, AT_SYMLINK_NOFOLLOW);
249 		if (rc == -1) {
250 			ERR(sess, "%s: utimensat", f->path);
251 			return -1;
252 		}
253 		LOG4(sess, "%s: updated symlink date", f->path);
254 	}
255 
256 	/*
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) {
262 		rc = fchmodat(p->rootfd,
263 			f->path, f->st.mode, AT_SYMLINK_NOFOLLOW);
264 		if (rc == -1) {
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;
284 	int		 rc;
285 	const struct flist *f;
286 
287 	f = &p->fl[p->idx];
288 	assert(S_ISDIR(f->st.mode));
289 
290 	if (!sess->opts->recursive) {
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 
298 	assert(p->rootfd != -1);
299 	rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
300 	if (rc == -1 && errno != ENOENT) {
301 		WARN(sess, "%s: fstatat", f->path);
302 		return -1;
303 	} else if (rc != -1 && !S_ISDIR(st.st_mode)) {
304 		WARNX(sess, "%s: not a directory", f->path);
305 		return -1;
306 	} else if (rc != -1) {
307 		/*
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);
324 	if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) {
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 
351 	if (!sess->opts->recursive)
352 		return 1;
353 	else if (sess->opts->dry_run)
354 		return 1;
355 
356 	if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
357 		ERR(sess, "%s: fstatat", f->path);
358 		return 0;
359 	} else if (!S_ISDIR(st.st_mode)) {
360 		WARNX(sess, "%s: not a directory", f->path);
361 		return 0;
362 	}
363 
364 	/*
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 
369 	if (u->newdir[idx] ||
370 	    (sess->opts->preserve_times &&
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);
377 		if (rc == -1) {
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 
389 	if (u->newdir[idx] ||
390 	    (sess->opts->preserve_perms &&
391 	     st.st_mode != f->st.mode)) {
392 		rc = fchmodat(u->rootfd, f->path, f->st.mode, 0);
393 		if (rc == -1) {
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);
419 		if (!io_write_int(sess, p->fdout, p->idx)) {
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);
437 	if (*filefd != -1 || errno == ENOENT)
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 *
449 upload_alloc(struct sess *sess, int rootfd, int fdout,
450 	size_t clen, const struct flist *fl, size_t flsz, mode_t msk)
451 {
452 	struct upload	*p;
453 
454 	if ((p = calloc(1, sizeof(struct upload))) == NULL) {
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));
467 	if (p->newdir == NULL) {
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 
483 	if (p == NULL)
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
499 rsync_uploader(struct upload *u, int *fileinfd,
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 
511 	assert(u->state != UPLOAD_FINISHED);
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 
520 	if (u->state == UPLOAD_WRITE_LOCAL) {
521 		assert(NULL != u->buf);
522 		assert(*fileoutfd != -1);
523 		assert(*fileinfd == -1);
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);
537 			c = io_write_buf(sess, u->fdout,
538 				u->buf + u->bufpos, sz);
539 			if (c == 0) {
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 
548 		/*
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 
566 	if (u->state == UPLOAD_FIND_NEXT) {
567 		assert(*fileinfd == -1);
568 		assert(*fileoutfd != -1);
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 
586 		/*
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) {
593 			assert(*fileinfd == -1);
594 			if (!io_write_int(sess, u->fdout, -1)) {
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;
607 		if (u->state == UPLOAD_READ_LOCAL)
608 			return 1;
609 	}
610 
611 	/*
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 
617 	if (u->state == UPLOAD_READ_LOCAL) {
618 		assert(*fileinfd != -1);
619 		assert(*fileoutfd == -1);
620 
621 		if (fstat(*fileinfd, &st) == -1) {
622 			WARN(sess, "%s: fstat", u->fl[u->idx].path);
623 			close(*fileinfd);
624 			*fileinfd = -1;
625 			return -1;
626 		} else if (!S_ISREG(st.st_mode)) {
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 
652 	assert(u->state == UPLOAD_WRITE_LOCAL);
653 	memset(&blk, 0, sizeof(struct blkset));
654 	blk.csum = u->csumlen;
655 
656 	if (*fileinfd != -1 && st.st_size > 0) {
657 		mapsz = st.st_size;
658 		map = mmap(NULL, mapsz,
659 			PROT_READ, MAP_SHARED, *fileinfd, 0);
660 		if (map == MAP_FAILED) {
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));
671 		if (blk.blks == NULL) {
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++) {
681 			init_blk(&blk.blks[i],
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",
690 			u->fl[u->idx].path, (intmax_t)blk.size,
691 			blk.blksz);
692 	} else {
693 		if (*fileinfd != -1) {
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 
701 	assert(*fileinfd == -1);
702 
703 	/* Make sure the block metadata buffer is big enough. */
704 
705 	u->bufsz =
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 */
711 	     blk.blksz *
712 	     (sizeof(int32_t) + /* short checksum */
713 	      blk.csum); /* long checksum */
714 
715 	if (u->bufsz > u->bufmax) {
716 		if ((bufp = realloc(u->buf, u->bufsz)) == NULL) {
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++) {
731 		io_buffer_int(sess, u->buf, &pos, u->bufsz,
732 			blk.blks[i].chksum_short);
733 		io_buffer_buf(sess, u->buf, &pos, u->bufsz,
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 
760 	if (!sess->opts->preserve_times &&
761 	     !sess->opts->preserve_perms)
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))
768 			if (!post_dir(sess, u, i))
769 				return 0;
770 
771 	return 1;
772 }
773