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