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