Annotation of src/usr.bin/rsync/uploader.c, Revision 1.10
1.10 ! florian 1: /* $Id: uploader.c,v 1.9 2019/02/16 10:46:22 florian 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.7 deraadt 74: LOG1(sess, "%s%s", f->path, ('/' == f->path[sz - 1]) ? "" : "/");
1.1 benno 75: }
76:
77: /*
78: * Log a link by emitting the file and the target, just to show the
79: * operator that we're a link.
80: */
81: static void
82: log_link(struct sess *sess, const struct flist *f)
83: {
84:
1.3 deraadt 85: if (!sess->opts->server)
1.1 benno 86: LOG1(sess, "%s -> %s", f->path, f->link);
87: }
88:
89: /*
90: * Simply log the filename.
91: */
92: static void
93: log_file(struct sess *sess, const struct flist *f)
94: {
95:
1.3 deraadt 96: if (!sess->opts->server)
1.1 benno 97: LOG1(sess, "%s", f->path);
98: }
99:
100: /*
101: * Prepare the overall block set's metadata.
102: * We always have at least one block.
103: * The block size is an important part of the algorithm.
104: * I use the same heuristic as the reference rsync, but implemented in a
105: * bit more of a straightforward way.
106: * In general, the individual block length is the rounded square root of
107: * the total file size.
108: * The minimum block length is 700.
109: */
110: static void
111: init_blkset(struct blkset *p, off_t sz)
112: {
113: double v;
114:
115: if (sz >= (BLOCK_SIZE_MIN * BLOCK_SIZE_MIN)) {
116: /* Simple rounded-up integer square root. */
117:
118: v = sqrt(sz);
119: p->len = ceil(v);
120:
1.2 benno 121: /*
1.1 benno 122: * Always be a multiple of eight.
123: * There's no reason to do this, but rsync does.
124: */
125:
126: if ((p->len % 8) > 0)
127: p->len += 8 - (p->len % 8);
128: } else
129: p->len = BLOCK_SIZE_MIN;
130:
131: p->size = sz;
1.4 deraadt 132: if ((p->blksz = sz / p->len) == 0)
1.1 benno 133: p->rem = sz;
134: else
135: p->rem = sz % p->len;
136:
137: /* If we have a remainder, then we need an extra block. */
138:
139: if (p->rem)
140: p->blksz++;
141: }
142:
143: /*
144: * For each block, prepare the block's metadata.
145: * We use the mapped "map" file to set our checksums.
146: */
147: static void
148: init_blk(struct blk *p, const struct blkset *set, off_t offs,
149: size_t idx, const void *map, const struct sess *sess)
150: {
151:
1.4 deraadt 152: assert(map != MAP_FAILED);
1.1 benno 153:
154: /* Block length inherits for all but the last. */
155:
156: p->idx = idx;
157: p->len = idx < set->blksz - 1 ? set->len : set->rem;
158: p->offs = offs;
159:
160: p->chksum_short = hash_fast(map + offs, p->len);
161: hash_slow(map + offs, p->len, p->chksum_long, sess);
162: }
163:
164: /*
165: * Return <0 on failure 0 on success.
166: */
167: static int
168: pre_link(struct upload *p, struct sess *sess)
169: {
1.9 florian 170: struct stat st;
171: struct timespec tv[2];
172: const struct flist *f;
173: int rc, newlink = 0, updatelink = 0;
174: mode_t mode;
175: char *b;
1.1 benno 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.9 florian 193: if (S_ISDIR(st.st_mode)) {
194: if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
195: WARN(sess, "%s", f->path);
196: return -1;
197: }
198: }
199: rc = -1; /* overwrite object with symlink */
1.4 deraadt 200: } else if (rc == -1 && errno != ENOENT) {
1.1 benno 201: WARN(sess, "%s: fstatat", f->path);
202: return -1;
203: }
204:
205: /*
206: * If the symbolic link already exists, then make sure that it
207: * points to the correct place.
208: */
209:
1.9 florian 210: if (rc != -1) {
1.1 benno 211: b = symlinkat_read(sess, p->rootfd, f->path);
1.4 deraadt 212: if (b == NULL) {
1.1 benno 213: ERRX1(sess, "%s: symlinkat_read", f->path);
214: return -1;
215: }
216: if (strcmp(f->link, b)) {
217: free(b);
218: b = NULL;
219: LOG3(sess, "%s: updating "
220: "symlink: %s", f->path, f->link);
1.9 florian 221: updatelink = 1;
1.2 benno 222: }
1.1 benno 223: free(b);
1.9 florian 224: b = NULL;
225: }
226:
227: if (rc == -1 || updatelink) {
228: LOG3(sess, "%s: creating "
229: "symlink: %s", f->path, f->link);
230:
231: if (mktemplate(&b, f->path, sess->opts->recursive) == -1) {
232: ERR(sess, "asprintf");
233: return -1;
234: }
235: if (mkstemplinkat(f->link, p->rootfd, b) == NULL) {
236: WARN(sess, "%s: symlinkat", b);
237: free(b);
238: return -1;
239: }
240: newlink = 1;
1.1 benno 241: }
242:
1.6 florian 243: /*
244: * Optionally preserve times/perms on the symlink.
245: * FIXME: run rsync_set_metadata()?
246: */
1.1 benno 247:
248: if (sess->opts->preserve_times) {
1.8 deraadt 249: struct timeval now;
250:
251: gettimeofday(&now, NULL);
252: TIMEVAL_TO_TIMESPEC(&now, &tv[0]);
1.1 benno 253: tv[1].tv_sec = f->st.mtime;
254: tv[1].tv_nsec = 0;
1.9 florian 255: rc = utimensat(p->rootfd, newlink ? b : f->path, tv,
256: AT_SYMLINK_NOFOLLOW);
1.4 deraadt 257: if (rc == -1) {
1.9 florian 258: ERR(sess, "%s: futimes", f->path);
259: if (newlink) {
260: (void)unlinkat(p->rootfd, b, 0);
261: free(b);
262: }
1.1 benno 263: return -1;
264: }
265: LOG4(sess, "%s: updated symlink date", f->path);
266: }
1.2 benno 267:
1.9 florian 268: if (newlink || sess->opts->preserve_perms) {
269: if (updatelink && !sess->opts->preserve_perms)
270: /* carry over permissions from replaced symlink */
271: mode = st.st_mode;
272: else
273: mode = f->st.mode;
1.1 benno 274:
1.9 florian 275: rc = fchmodat(p->rootfd, newlink ? b : f->path, mode,
276: AT_SYMLINK_NOFOLLOW);
1.4 deraadt 277: if (rc == -1) {
1.9 florian 278: ERR(sess, "%s: fchmodat", newlink ? b : f->path);
279: if (newlink) {
280: (void)unlinkat(p->rootfd, b, 0);
281: free(b);
282: }
1.1 benno 283: return -1;
284: }
285: LOG4(sess, "%s: updated symlink mode", f->path);
1.9 florian 286: }
287:
288: if (newlink) {
289: if (renameat(p->rootfd, b, p->rootfd, f->path) == -1) {
290: ERR(sess, "%s: renameat %s", b, f->path);
291: (void)unlinkat(p->rootfd, b, 0);
292: free(b);
293: return -1;
294: }
295: free(b);
1.1 benno 296: }
297:
298: log_link(sess, f);
299: return 0;
300: }
301:
302: /*
303: * If not found, create the destination directory in prefix order.
304: * Create directories using the existing umask.
305: * Return <0 on failure 0 on success.
306: */
307: static int
308: pre_dir(const struct upload *p, struct sess *sess)
309: {
310: struct stat st;
1.2 benno 311: int rc;
1.1 benno 312: const struct flist *f;
313:
314: f = &p->fl[p->idx];
315: assert(S_ISDIR(f->st.mode));
316:
1.3 deraadt 317: if (!sess->opts->recursive) {
1.1 benno 318: WARNX(sess, "%s: ignoring directory", f->path);
319: return 0;
320: } else if (sess->opts->dry_run) {
321: log_dir(sess, f);
322: return 0;
323: }
324:
1.4 deraadt 325: assert(p->rootfd != -1);
1.1 benno 326: rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
1.4 deraadt 327: if (rc == -1 && errno != ENOENT) {
1.1 benno 328: WARN(sess, "%s: fstatat", f->path);
329: return -1;
1.4 deraadt 330: } else if (rc != -1 && !S_ISDIR(st.st_mode)) {
1.1 benno 331: WARNX(sess, "%s: not a directory", f->path);
332: return -1;
1.4 deraadt 333: } else if (rc != -1) {
1.2 benno 334: /*
1.1 benno 335: * FIXME: we should fchmod the permissions here as well,
336: * as we may locally have shut down writing into the
337: * directory and that doesn't work.
338: */
339: LOG3(sess, "%s: updating directory", f->path);
340: return 0;
341: }
342:
343: /*
344: * We want to make the directory with default permissions (using
345: * our old umask, which we've since unset), then adjust
346: * permissions (assuming preserve_perms or new) afterward in
347: * case it's u-w or something.
348: */
349:
350: LOG3(sess, "%s: creating directory", f->path);
1.4 deraadt 351: if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) {
1.1 benno 352: WARN(sess, "%s: mkdirat", f->path);
353: return -1;
354: }
355:
356: p->newdir[p->idx] = 1;
357: log_dir(sess, f);
358: return 0;
359: }
360:
361: /*
362: * Process the directory time and mode for "idx" in the file list.
363: * Returns zero on failure, non-zero on success.
364: */
365: static int
366: post_dir(struct sess *sess, const struct upload *u, size_t idx)
367: {
368: struct timespec tv[2];
369: int rc;
370: struct stat st;
371: const struct flist *f;
372:
373: f = &u->fl[idx];
374: assert(S_ISDIR(f->st.mode));
375:
376: /* We already warned about the directory in pre_process_dir(). */
377:
1.3 deraadt 378: if (!sess->opts->recursive)
1.1 benno 379: return 1;
380: else if (sess->opts->dry_run)
381: return 1;
382:
1.4 deraadt 383: if (fstatat(u->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW) == -1) {
1.1 benno 384: ERR(sess, "%s: fstatat", f->path);
385: return 0;
1.3 deraadt 386: } else if (!S_ISDIR(st.st_mode)) {
1.1 benno 387: WARNX(sess, "%s: not a directory", f->path);
388: return 0;
389: }
390:
1.2 benno 391: /*
1.1 benno 392: * Update the modification time if we're a new directory *or* if
393: * we're preserving times and the time has changed.
1.6 florian 394: * FIXME: run rsync_set_metadata()?
1.1 benno 395: */
396:
1.2 benno 397: if (u->newdir[idx] ||
398: (sess->opts->preserve_times &&
1.1 benno 399: st.st_mtime != f->st.mtime)) {
400: tv[0].tv_sec = time(NULL);
401: tv[0].tv_nsec = 0;
402: tv[1].tv_sec = f->st.mtime;
403: tv[1].tv_nsec = 0;
404: rc = utimensat(u->rootfd, f->path, tv, 0);
1.4 deraadt 405: if (rc == -1) {
1.1 benno 406: ERR(sess, "%s: utimensat", f->path);
407: return 0;
408: }
409: LOG4(sess, "%s: updated date", f->path);
410: }
411:
412: /*
413: * Update the mode if we're a new directory *or* if we're
414: * preserving modes and it has changed.
415: */
416:
1.2 benno 417: if (u->newdir[idx] ||
1.1 benno 418: (sess->opts->preserve_perms &&
419: st.st_mode != f->st.mode)) {
420: rc = fchmodat(u->rootfd, f->path, f->st.mode, 0);
1.4 deraadt 421: if (rc == -1) {
1.1 benno 422: ERR(sess, "%s: fchmodat", f->path);
423: return 0;
424: }
425: LOG4(sess, "%s: updated mode", f->path);
426: }
427:
428: return 1;
429: }
430:
431: /*
432: * Try to open the file at the current index.
433: * If the file does not exist, returns with success.
434: * Return <0 on failure, 0 on success w/nothing to be done, >0 on
435: * success and the file needs attention.
436: */
437: static int
438: pre_file(const struct upload *p, int *filefd, struct sess *sess)
439: {
440: const struct flist *f;
441:
442: f = &p->fl[p->idx];
443: assert(S_ISREG(f->st.mode));
444:
445: if (sess->opts->dry_run) {
446: log_file(sess, f);
1.3 deraadt 447: if (!io_write_int(sess, p->fdout, p->idx)) {
1.1 benno 448: ERRX1(sess, "io_write_int");
449: return -1;
450: }
451: return 0;
452: }
453:
454: /*
455: * For non dry-run cases, we'll write the acknowledgement later
456: * in the rsync_uploader() function because we need to wait for
457: * the open() call to complete.
458: * If the call to openat() fails with ENOENT, there's a
459: * fast-path between here and the write function, so we won't do
460: * any blocking between now and then.
461: */
462:
463: *filefd = openat(p->rootfd, f->path,
464: O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0);
1.4 deraadt 465: if (*filefd != -1 || errno == ENOENT)
1.1 benno 466: return 1;
467: ERR(sess, "%s: openat", f->path);
468: return -1;
469: }
470:
471: /*
472: * Allocate an uploader object in the correct state to start.
473: * Returns NULL on failure or the pointer otherwise.
474: * On success, upload_free() must be called with the allocated pointer.
475: */
476: struct upload *
1.2 benno 477: upload_alloc(struct sess *sess, int rootfd, int fdout,
1.1 benno 478: size_t clen, const struct flist *fl, size_t flsz, mode_t msk)
479: {
480: struct upload *p;
481:
1.4 deraadt 482: if ((p = calloc(1, sizeof(struct upload))) == NULL) {
1.1 benno 483: ERR(sess, "calloc");
484: return NULL;
485: }
486:
487: p->state = UPLOAD_FIND_NEXT;
488: p->oumask = msk;
489: p->rootfd = rootfd;
490: p->csumlen = clen;
491: p->fdout = fdout;
492: p->fl = fl;
493: p->flsz = flsz;
494: p->newdir = calloc(flsz, sizeof(int));
1.4 deraadt 495: if (p->newdir == NULL) {
1.1 benno 496: ERR(sess, "calloc");
497: free(p);
498: return NULL;
499: }
500: return p;
501: }
502:
503: /*
504: * Perform all cleanups and free.
505: * Passing a NULL to this function is ok.
506: */
507: void
508: upload_free(struct upload *p)
509: {
510:
1.4 deraadt 511: if (p == NULL)
1.1 benno 512: return;
513: free(p->newdir);
514: free(p->buf);
515: free(p);
516: }
517:
518: /*
519: * Iterates through all available files and conditionally gets the file
520: * ready for processing to check whether it's up to date.
521: * If not up to date or empty, sends file information to the sender.
522: * If returns 0, we've processed all files there are to process.
523: * If returns >0, we're waiting for POLLIN or POLLOUT data.
524: * Otherwise returns <0, which is an error.
525: */
526: int
1.2 benno 527: rsync_uploader(struct upload *u, int *fileinfd,
1.1 benno 528: struct sess *sess, int *fileoutfd)
529: {
1.5 florian 530: struct blkset blk;
531: struct stat st;
532: void *map, *bufp;
533: size_t i, mapsz, pos, sz;
534: off_t offs;
535: int c;
536: const struct flist *f;
1.1 benno 537:
538: /* This should never get called. */
539:
1.4 deraadt 540: assert(u->state != UPLOAD_FINISHED);
1.1 benno 541:
542: /*
543: * If we have an upload in progress, then keep writing until the
544: * buffer has been fully written.
545: * We must only have the output file descriptor working and also
546: * have a valid buffer to write.
547: */
548:
1.4 deraadt 549: if (u->state == UPLOAD_WRITE_LOCAL) {
1.1 benno 550: assert(NULL != u->buf);
1.4 deraadt 551: assert(*fileoutfd != -1);
552: assert(*fileinfd == -1);
1.1 benno 553:
554: /*
555: * Unfortunately, we need to chunk these: if we're
556: * the server side of things, then we're multiplexing
557: * output and need to wrap this in chunks.
558: * This is a major deficiency of rsync.
559: * FIXME: add a "fast-path" mode that simply dumps out
560: * the buffer non-blocking if we're not mplexing.
561: */
562:
563: if (u->bufpos < u->bufsz) {
564: sz = MAX_CHUNK < (u->bufsz - u->bufpos) ?
565: MAX_CHUNK : (u->bufsz - u->bufpos);
1.2 benno 566: c = io_write_buf(sess, u->fdout,
1.1 benno 567: u->buf + u->bufpos, sz);
1.4 deraadt 568: if (c == 0) {
1.1 benno 569: ERRX1(sess, "io_write_nonblocking");
570: return -1;
571: }
572: u->bufpos += sz;
573: if (u->bufpos < u->bufsz)
574: return 1;
575: }
576:
1.2 benno 577: /*
1.1 benno 578: * Let the UPLOAD_FIND_NEXT state handle things if we
579: * finish, as we'll need to write a POLLOUT message and
580: * not have a writable descriptor yet.
581: */
582:
583: u->state = UPLOAD_FIND_NEXT;
584: u->idx++;
585: return 1;
586: }
587:
588: /*
589: * If we invoke the uploader without a file currently open, then
590: * we iterate through til the next available regular file and
591: * start the opening process.
592: * This means we must have the output file descriptor working.
593: */
594:
1.4 deraadt 595: if (u->state == UPLOAD_FIND_NEXT) {
596: assert(*fileinfd == -1);
597: assert(*fileoutfd != -1);
1.1 benno 598:
599: for ( ; u->idx < u->flsz; u->idx++) {
600: if (S_ISDIR(u->fl[u->idx].st.mode))
601: c = pre_dir(u, sess);
602: else if (S_ISLNK(u->fl[u->idx].st.mode))
603: c = pre_link(u, sess);
604: else if (S_ISREG(u->fl[u->idx].st.mode))
605: c = pre_file(u, fileinfd, sess);
606: else
607: c = 0;
608:
609: if (c < 0)
610: return -1;
611: else if (c > 0)
612: break;
613: }
614:
1.2 benno 615: /*
1.1 benno 616: * Whether we've finished writing files or not, we
617: * disable polling on the output channel.
618: */
619:
620: *fileoutfd = -1;
621: if (u->idx == u->flsz) {
1.4 deraadt 622: assert(*fileinfd == -1);
1.3 deraadt 623: if (!io_write_int(sess, u->fdout, -1)) {
1.1 benno 624: ERRX1(sess, "io_write_int");
625: return -1;
626: }
627: u->state = UPLOAD_FINISHED;
628: LOG4(sess, "uploader: finished");
629: return 0;
630: }
631:
632: /* Go back to the event loop, if necessary. */
633:
634: u->state = -1 == *fileinfd ?
635: UPLOAD_WRITE_LOCAL : UPLOAD_READ_LOCAL;
1.4 deraadt 636: if (u->state == UPLOAD_READ_LOCAL)
1.1 benno 637: return 1;
638: }
639:
1.2 benno 640: /*
1.1 benno 641: * If an input file is open, stat it and see if it's already up
642: * to date, in which case close it and go to the next one.
643: * Either way, we don't have a write channel open.
644: */
645:
1.4 deraadt 646: if (u->state == UPLOAD_READ_LOCAL) {
647: assert(*fileinfd != -1);
648: assert(*fileoutfd == -1);
1.5 florian 649: f = &u->fl[u->idx];
1.1 benno 650:
1.4 deraadt 651: if (fstat(*fileinfd, &st) == -1) {
1.5 florian 652: ERR(sess, "%s: fstat", f->path);
1.1 benno 653: close(*fileinfd);
654: *fileinfd = -1;
655: return -1;
1.3 deraadt 656: } else if (!S_ISREG(st.st_mode)) {
1.5 florian 657: ERRX(sess, "%s: not regular", f->path);
1.1 benno 658: close(*fileinfd);
659: *fileinfd = -1;
660: return -1;
661: }
662:
1.5 florian 663: if (st.st_size == f->st.size &&
664: st.st_mtime == f->st.mtime) {
665: LOG3(sess, "%s: skipping: up to date", f->path);
666: if (!rsync_set_metadata
667: (sess, 0, *fileinfd, f, f->path)) {
668: ERRX1(sess, "rsync_set_metadata");
669: close(*fileinfd);
670: *fileinfd = -1;
671: return -1;
672: }
1.1 benno 673: close(*fileinfd);
674: *fileinfd = -1;
675: *fileoutfd = u->fdout;
676: u->state = UPLOAD_FIND_NEXT;
677: u->idx++;
678: return 1;
679: }
680:
681: /* Fallthrough... */
682:
683: u->state = UPLOAD_WRITE_LOCAL;
684: }
685:
686: /* Initialies our blocks. */
687:
1.4 deraadt 688: assert(u->state == UPLOAD_WRITE_LOCAL);
1.1 benno 689: memset(&blk, 0, sizeof(struct blkset));
690: blk.csum = u->csumlen;
691:
1.4 deraadt 692: if (*fileinfd != -1 && st.st_size > 0) {
1.1 benno 693: mapsz = st.st_size;
1.7 deraadt 694: map = mmap(NULL, mapsz, PROT_READ, MAP_SHARED, *fileinfd, 0);
1.4 deraadt 695: if (map == MAP_FAILED) {
1.1 benno 696: WARN(sess, "%s: mmap", u->fl[u->idx].path);
697: close(*fileinfd);
698: *fileinfd = -1;
699: return -1;
700: }
701:
702: init_blkset(&blk, st.st_size);
703: assert(blk.blksz);
704:
705: blk.blks = calloc(blk.blksz, sizeof(struct blk));
1.4 deraadt 706: if (blk.blks == NULL) {
1.1 benno 707: ERR(sess, "calloc");
708: munmap(map, mapsz);
709: close(*fileinfd);
710: *fileinfd = -1;
711: return -1;
712: }
713:
714: offs = 0;
715: for (i = 0; i < blk.blksz; i++) {
1.2 benno 716: init_blk(&blk.blks[i],
1.1 benno 717: &blk, offs, i, map, sess);
718: offs += blk.len;
719: }
720:
721: munmap(map, mapsz);
722: close(*fileinfd);
723: *fileinfd = -1;
724: LOG3(sess, "%s: mapped %jd B with %zu blocks",
1.2 benno 725: u->fl[u->idx].path, (intmax_t)blk.size,
1.1 benno 726: blk.blksz);
727: } else {
1.4 deraadt 728: if (*fileinfd != -1) {
1.1 benno 729: close(*fileinfd);
730: *fileinfd = -1;
731: }
732: blk.len = MAX_CHUNK; /* Doesn't matter. */
733: LOG3(sess, "%s: not mapped", u->fl[u->idx].path);
734: }
735:
1.4 deraadt 736: assert(*fileinfd == -1);
1.1 benno 737:
738: /* Make sure the block metadata buffer is big enough. */
739:
1.2 benno 740: u->bufsz =
1.1 benno 741: sizeof(int32_t) + /* identifier */
742: sizeof(int32_t) + /* block count */
743: sizeof(int32_t) + /* block length */
744: sizeof(int32_t) + /* checksum length */
745: sizeof(int32_t) + /* block remainder */
1.2 benno 746: blk.blksz *
1.1 benno 747: (sizeof(int32_t) + /* short checksum */
748: blk.csum); /* long checksum */
749:
750: if (u->bufsz > u->bufmax) {
1.4 deraadt 751: if ((bufp = realloc(u->buf, u->bufsz)) == NULL) {
1.1 benno 752: ERR(sess, "realloc");
753: return -1;
754: }
755: u->buf = bufp;
756: u->bufmax = u->bufsz;
757: }
758:
759: u->bufpos = pos = 0;
760: io_buffer_int(sess, u->buf, &pos, u->bufsz, u->idx);
761: io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.blksz);
762: io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.len);
763: io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.csum);
764: io_buffer_int(sess, u->buf, &pos, u->bufsz, blk.rem);
765: for (i = 0; i < blk.blksz; i++) {
1.2 benno 766: io_buffer_int(sess, u->buf, &pos, u->bufsz,
1.1 benno 767: blk.blks[i].chksum_short);
1.2 benno 768: io_buffer_buf(sess, u->buf, &pos, u->bufsz,
1.1 benno 769: blk.blks[i].chksum_long, blk.csum);
770: }
771: assert(pos == u->bufsz);
772:
773: /* Reenable the output poller and clean up. */
774:
775: *fileoutfd = u->fdout;
776: free(blk.blks);
777: return 1;
778: }
779:
780: /*
781: * Fix up the directory permissions and times post-order.
782: * We can't fix up directory permissions in place because the server may
783: * want us to have overly-tight permissions---say, those that don't
784: * allow writing into the directory.
785: * We also need to do our directory times post-order because making
786: * files within the directory will change modification times.
787: * Returns zero on failure, non-zero on success.
788: */
789: int
790: rsync_uploader_tail(struct upload *u, struct sess *sess)
791: {
792: size_t i;
793:
794:
1.3 deraadt 795: if (!sess->opts->preserve_times &&
796: !sess->opts->preserve_perms)
1.1 benno 797: return 1;
798:
799: LOG2(sess, "fixing up directory times and permissions");
800:
801: for (i = 0; i < u->flsz; i++)
802: if (S_ISDIR(u->fl[i].st.mode))
1.3 deraadt 803: if (!post_dir(sess, u, i))
1.1 benno 804: return 0;
805:
806: return 1;
807: }