Annotation of src/usr.bin/rsync/flist.c, Revision 1.6
1.6 ! benno 1: /* $Id: flist.c,v 1.5 2019/02/11 21:41:22 deraadt Exp $ */
1.1 benno 2: /*
3: * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <sys/param.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 <fts.h>
25: #include <search.h>
26: #include <stdio.h>
27: #include <stdlib.h>
28: #include <string.h>
29: #include <unistd.h>
30:
31: #include "extern.h"
32:
33: /*
34: * We allocate our file list in chunk sizes so as not to do it one by
35: * one.
36: * Preferrably we get one or two allocation.
37: */
38: #define FLIST_CHUNK_SIZE (1024)
39:
40: /*
41: * These flags are part of the rsync protocol.
42: * They are sent as the first byte for a file transmission and encode
43: * information that affects subsequent transmissions.
44: */
45: #define FLIST_MODE_SAME 0x0002 /* mode is repeat */
1.6 ! benno 46: #define FLIST_GID_SAME 0x0010 /* gid is repeat */
1.1 benno 47: #define FLIST_NAME_SAME 0x0020 /* name is repeat */
48: #define FLIST_NAME_LONG 0x0040 /* name >255 bytes */
49: #define FLIST_TIME_SAME 0x0080 /* time is repeat */
50:
51: /*
52: * Requied way to sort a filename list.
53: */
54: static int
55: flist_cmp(const void *p1, const void *p2)
56: {
57: const struct flist *f1 = p1, *f2 = p2;
58:
59: return strcmp(f1->wpath, f2->wpath);
60: }
61:
62: /*
63: * Deduplicate our file list (which may be zero-length).
64: * Returns zero on failure, non-zero on success.
65: */
66: static int
67: flist_dedupe(struct sess *sess, struct flist **fl, size_t *sz)
68: {
1.2 benno 69: size_t i, j;
1.1 benno 70: struct flist *new;
71: struct flist *f, *fnext;
72:
1.5 deraadt 73: if (*sz == 0)
1.1 benno 74: return 1;
75:
76: /* Create a new buffer, "new", and copy. */
77:
78: new = calloc(*sz, sizeof(struct flist));
1.5 deraadt 79: if (new == NULL) {
1.1 benno 80: ERR(sess, "calloc");
81: return 0;
82: }
83:
84: for (i = j = 0; i < *sz - 1; i++) {
85: f = &(*fl)[i];
86: fnext = &(*fl)[i + 1];
87:
88: if (strcmp(f->wpath, fnext->wpath)) {
89: new[j++] = *f;
90: continue;
91: }
92:
93: /*
94: * Our working (destination) paths are the same.
95: * If the actual file is the same (as given on the
96: * command-line), then we can just discard the first.
97: * Otherwise, we need to bail out: it means we have two
98: * different files with the relative path on the
99: * destination side.
100: */
101:
1.5 deraadt 102: if (strcmp(f->path, fnext->path) == 0) {
1.1 benno 103: new[j++] = *f;
104: i++;
105: WARNX(sess, "%s: duplicate path: %s",
1.3 benno 106: f->wpath, f->path);
1.1 benno 107: free(fnext->path);
108: free(fnext->link);
109: fnext->path = fnext->link = NULL;
110: continue;
111: }
112:
113: ERRX(sess, "%s: duplicate working path for "
1.3 benno 114: "possibly different file: %s, %s",
115: f->wpath, f->path, fnext->path);
1.1 benno 116: free(new);
117: return 0;
118: }
119:
120: /* Don't forget the last entry. */
121:
122: if (i == *sz - 1)
123: new[j++] = (*fl)[i];
124:
125: /*
126: * Reassign to the deduplicated array.
127: * If we started out with *sz > 0, which we check for at the
128: * beginning, then we'll always continue having *sz > 0.
129: */
130:
131: free(*fl);
132: *fl = new;
133: *sz = j;
134: assert(*sz);
135: return 1;
136: }
137:
138: /*
139: * We're now going to find our top-level directories.
140: * This only applies to recursive mode.
141: * If we have the first element as the ".", then that's the "top
142: * directory" of our transfer.
143: * Otherwise, mark up all top-level directories in the set.
144: */
145: static void
146: flist_topdirs(struct sess *sess, struct flist *fl, size_t flsz)
147: {
1.2 benno 148: size_t i;
1.1 benno 149: const char *cp;
150:
1.4 deraadt 151: if (!sess->opts->recursive)
1.1 benno 152: return;
153:
154: if (flsz && strcmp(fl[0].wpath, ".")) {
155: for (i = 0; i < flsz; i++) {
1.4 deraadt 156: if (!S_ISDIR(fl[i].st.mode))
1.1 benno 157: continue;
158: cp = strchr(fl[i].wpath, '/');
1.5 deraadt 159: if (cp != NULL && cp[1] != '\0')
1.1 benno 160: continue;
161: fl[i].st.flags |= FLSTAT_TOP_DIR;
162: LOG4(sess, "%s: top-level", fl[i].wpath);
163: }
164: } else if (flsz) {
165: fl[0].st.flags |= FLSTAT_TOP_DIR;
166: LOG4(sess, "%s: top-level", fl[0].wpath);
167: }
168: }
169:
170: /*
171: * Filter through the fts() file information.
172: * We want directories (pre-order), regular files, and symlinks.
173: * Everything else is skipped and possibly warned about.
174: * Return zero to skip, non-zero to examine.
175: */
176: static int
177: flist_fts_check(struct sess *sess, FTSENT *ent)
178: {
179:
1.5 deraadt 180: if (ent->fts_info == FTS_F ||
181: ent->fts_info == FTS_D ||
182: ent->fts_info == FTS_SL ||
183: ent->fts_info == FTS_SLNONE)
1.1 benno 184: return 1;
185:
1.5 deraadt 186: if (ent->fts_info == FTS_DC) {
1.1 benno 187: WARNX(sess, "%s: directory cycle", ent->fts_path);
1.5 deraadt 188: } else if (ent->fts_info == FTS_DNR) {
1.1 benno 189: errno = ent->fts_errno;
190: WARN(sess, "%s: unreadable directory", ent->fts_path);
1.5 deraadt 191: } else if (ent->fts_info == FTS_DOT) {
1.1 benno 192: WARNX(sess, "%s: skipping dot-file", ent->fts_path);
1.5 deraadt 193: } else if (ent->fts_info == FTS_ERR) {
1.1 benno 194: errno = ent->fts_errno;
195: WARN(sess, "%s", ent->fts_path);
1.5 deraadt 196: } else if (ent->fts_info == FTS_DEFAULT) {
1.1 benno 197: WARNX(sess, "%s: skipping special", ent->fts_path);
1.5 deraadt 198: } else if (ent->fts_info == FTS_NS) {
1.1 benno 199: errno = ent->fts_errno;
200: WARN(sess, "%s: could not stat", ent->fts_path);
201: }
202:
203: return 0;
204: }
205:
206: /*
207: * Copy necessary elements in "st" into the fields of "f".
208: */
209: static void
210: flist_copy_stat(struct flist *f, const struct stat *st)
211: {
212: f->st.mode = st->st_mode;
213: f->st.uid = st->st_uid;
214: f->st.gid = st->st_gid;
215: f->st.size = st->st_size;
216: f->st.mtime = st->st_mtime;
217: }
218:
219: void
220: flist_free(struct flist *f, size_t sz)
221: {
222: size_t i;
223:
1.5 deraadt 224: if (f == NULL)
1.1 benno 225: return;
226:
227: for (i = 0; i < sz; i++) {
228: free(f[i].path);
229: free(f[i].link);
230: }
231: free(f);
232: }
233:
234: /*
235: * Serialise our file list (which may be zero-length) to the wire.
236: * Makes sure that the receiver isn't going to block on sending us
237: * return messages on the log channel.
238: * Return zero on failure, non-zero on success.
239: */
240: int
1.3 benno 241: flist_send(struct sess *sess, int fdin, int fdout, const struct flist *fl,
242: size_t flsz)
1.1 benno 243: {
244: size_t i, fnlen;
245: uint8_t flag;
246: const struct flist *f;
247: const char *fn;
248:
249: /* Double-check that we've no pending multiplexed data. */
250:
251: LOG2(sess, "sending file metadata list: %zu", flsz);
252:
253: for (i = 0; i < flsz; i++) {
254: f = &fl[i];
255: fn = f->wpath;
256: fnlen = strlen(f->wpath);
257: assert(fnlen > 0);
258:
1.2 benno 259: /*
1.1 benno 260: * If applicable, unclog the read buffer.
261: * This happens when the receiver has a lot of log
262: * messages and all we're doing is sending our file list
263: * without checking for messages.
264: */
265:
266: if (sess->mplex_reads &&
267: io_read_check(sess, fdin) &&
1.4 deraadt 268: !io_read_flush(sess, fdin)) {
1.1 benno 269: ERRX1(sess, "io_read_flush");
270: return 0;
271: }
272:
273: /*
274: * For ease, make all of our filenames be "long"
275: * regardless their actual length.
276: * This also makes sure that we don't transmit a zero
277: * byte unintentionally.
278: */
279:
280: flag = FLIST_NAME_LONG;
281:
282: LOG3(sess, "%s: sending file metadata: "
283: "size %jd, mtime %jd, mode %o",
284: fn, (intmax_t)f->st.size,
285: (intmax_t)f->st.mtime, f->st.mode);
286:
287: /* Now write to the wire. */
288: /* FIXME: buffer this. */
289:
1.4 deraadt 290: if (!io_write_byte(sess, fdout, flag)) {
1.1 benno 291: ERRX1(sess, "io_write_byte");
292: return 0;
1.4 deraadt 293: } else if (!io_write_int(sess, fdout, fnlen)) {
1.1 benno 294: ERRX1(sess, "io_write_int");
295: return 0;
1.4 deraadt 296: } else if (!io_write_buf(sess, fdout, fn, fnlen)) {
1.1 benno 297: ERRX1(sess, "io_write_buf");
298: return 0;
1.4 deraadt 299: } else if (!io_write_long(sess, fdout, f->st.size)) {
1.1 benno 300: ERRX1(sess, "io_write_long");
301: return 0;
1.4 deraadt 302: } else if (!io_write_int(sess, fdout, f->st.mtime)) {
1.1 benno 303: ERRX1(sess, "io_write_int");
304: return 0;
1.4 deraadt 305: } else if (!io_write_int(sess, fdout, f->st.mode)) {
1.1 benno 306: ERRX1(sess, "io_write_int");
307: return 0;
308: }
309:
1.6 ! benno 310: /* Conditional part: gid. */
! 311:
! 312: if (sess->opts->preserve_gids &&
! 313: ! io_write_int(sess, fdout, f->st.gid)) {
! 314: ERRX1(sess, "io_write_int");
! 315: return 0;
! 316: }
! 317:
! 318: /* Conditional part: link. */
1.1 benno 319:
320: if (S_ISLNK(f->st.mode) &&
321: sess->opts->preserve_links) {
322: fn = f->link;
323: fnlen = strlen(f->link);
1.4 deraadt 324: if (!io_write_int(sess, fdout, fnlen)) {
1.1 benno 325: ERRX1(sess, "io_write_int");
326: return 0;
327: }
1.4 deraadt 328: if (!io_write_buf(sess, fdout, fn, fnlen)) {
1.1 benno 329: ERRX1(sess, "io_write_int");
330: return 0;
331: }
332: }
333:
334: if (S_ISREG(f->st.mode))
335: sess->total_size += f->st.size;
336: }
337:
1.4 deraadt 338: if (!io_write_byte(sess, fdout, 0)) {
1.1 benno 339: ERRX1(sess, "io_write_byte");
340: return 0;
341: }
342:
343: return 1;
344: }
345:
346: /*
347: * Read the filename of a file list.
348: * This is the most expensive part of the file list transfer, so a lot
349: * of attention has gone into transmitting as little as possible.
350: * Micro-optimisation, but whatever.
351: * Fills in "f" with the full path on success.
352: * Returns zero on failure, non-zero on success.
353: */
354: static int
1.3 benno 355: flist_recv_name(struct sess *sess, int fd, struct flist *f, uint8_t flags,
356: char last[MAXPATHLEN])
1.1 benno 357: {
358: uint8_t bval;
359: size_t partial = 0;
360: size_t pathlen = 0, len;
361:
362: /*
363: * Read our filename.
364: * If we have FLIST_NAME_SAME, we inherit some of the last
365: * transmitted name.
366: * If we have FLIST_NAME_LONG, then the string length is greater
367: * than byte-size.
368: */
369:
370: if (FLIST_NAME_SAME & flags) {
1.4 deraadt 371: if (!io_read_byte(sess, fd, &bval)) {
1.1 benno 372: ERRX1(sess, "io_read_byte");
373: return 0;
374: }
375: partial = bval;
376: }
377:
378: /* Get the (possibly-remaining) filename length. */
379:
380: if (FLIST_NAME_LONG & flags) {
1.4 deraadt 381: if (!io_read_size(sess, fd, &pathlen)) {
1.1 benno 382: ERRX1(sess, "io_read_size");
383: return 0;
384: }
385: } else {
1.4 deraadt 386: if (!io_read_byte(sess, fd, &bval)) {
1.1 benno 387: ERRX1(sess, "io_read_byte");
388: return 0;
389: }
390: pathlen = bval;
391: }
392:
393: /* Allocate our full filename length. */
394: /* FIXME: maximum pathname length. */
395:
1.5 deraadt 396: if ((len = pathlen + partial) == 0) {
1.1 benno 397: ERRX(sess, "security violation: "
398: "zero-length pathname");
399: return 0;
400: }
401:
1.5 deraadt 402: if ((f->path = malloc(len + 1)) == NULL) {
1.1 benno 403: ERR(sess, "malloc");
404: return 0;
405: }
406: f->path[len] = '\0';
407:
408: if (FLIST_NAME_SAME & flags)
409: memcpy(f->path, last, partial);
410:
1.4 deraadt 411: if (!io_read_buf(sess, fd, f->path + partial, pathlen)) {
1.1 benno 412: ERRX1(sess, "io_read_buf");
413: return 0;
414: }
415:
1.5 deraadt 416: if (f->path[0] == '/') {
1.1 benno 417: ERRX(sess, "security violation: "
418: "absolute pathname: %s", f->path);
419: return 0;
420: }
421:
1.5 deraadt 422: if (strstr(f->path, "/../") != NULL ||
423: (len > 2 && strcmp(f->path + len - 3, "/..") == 0) ||
424: (len > 2 && strncmp(f->path, "../", 3) == 0) ||
425: strcmp(f->path, "..") == 0) {
1.1 benno 426: ERRX(sess, "%s: security violation: "
427: "backtracking pathname", f->path);
428: return 0;
429: }
430:
431: /* Record our last path and construct our filename. */
432:
433: strlcpy(last, f->path, MAXPATHLEN);
434: f->wpath = f->path;
435: return 1;
436: }
437:
438: /*
439: * Reallocate a file list in chunks of FLIST_CHUNK_SIZE;
440: * Returns zero on failure, non-zero on success.
441: */
442: static int
1.3 benno 443: flist_realloc(struct sess *sess, struct flist **fl, size_t *sz, size_t *max)
1.1 benno 444: {
445: void *pp;
446:
447: if (*sz + 1 <= *max) {
448: (*sz)++;
449: return 1;
450: }
451:
452: pp = recallocarray(*fl, *max,
453: *max + FLIST_CHUNK_SIZE, sizeof(struct flist));
1.5 deraadt 454: if (pp == NULL) {
1.1 benno 455: ERR(sess, "recallocarray");
456: return 0;
457: }
458: *fl = pp;
459: *max += FLIST_CHUNK_SIZE;
460: (*sz)++;
461: return 1;
462: }
463:
464: /*
465: * Copy a regular or symbolic link file "path" into "f".
466: * This handles the correct path creation and symbolic linking.
467: * Returns zero on failure, non-zero on success.
468: */
469: static int
1.3 benno 470: flist_append(struct sess *sess, struct flist *f, struct stat *st,
471: const char *path)
1.1 benno 472: {
473:
474: /*
475: * Copy the full path for local addressing and transmit
476: * only the filename part for the receiver.
477: */
478:
1.5 deraadt 479: if ((f->path = strdup(path)) == NULL) {
1.1 benno 480: ERR(sess, "strdup");
481: return 0;
482: }
483:
1.5 deraadt 484: if ((f->wpath = strrchr(f->path, '/')) == NULL)
1.1 benno 485: f->wpath = f->path;
486: else
487: f->wpath++;
488:
489: /*
490: * On the receiving end, we'll strip out all bits on the
491: * mode except for the file permissions.
492: * No need to warn about it here.
493: */
494:
495: flist_copy_stat(f, st);
496:
497: /* Optionally copy link information. */
498:
499: if (S_ISLNK(st->st_mode)) {
500: f->link = symlink_read(sess, f->path);
1.5 deraadt 501: if (f->link == NULL) {
1.1 benno 502: ERRX1(sess, "symlink_read");
503: return 0;
504: }
505: }
506:
507: return 1;
508: }
509:
510: /*
511: * Receive a file list from the wire, filling in length "sz" (which may
512: * possibly be zero) and list "flp" on success.
513: * Return zero on failure, non-zero on success.
514: */
515: int
516: flist_recv(struct sess *sess, int fd, struct flist **flp, size_t *sz)
517: {
518: struct flist *fl = NULL;
519: struct flist *ff;
520: const struct flist *fflast = NULL;
521: size_t flsz = 0, flmax = 0, lsz;
522: uint8_t flag;
523: char last[MAXPATHLEN];
524: uint64_t lval; /* temporary values... */
525: int32_t ival;
526:
527: last[0] = '\0';
528:
529: for (;;) {
1.4 deraadt 530: if (!io_read_byte(sess, fd, &flag)) {
1.1 benno 531: ERRX1(sess, "io_read_byte");
532: goto out;
1.5 deraadt 533: } else if (flag == 0)
1.1 benno 534: break;
535:
1.4 deraadt 536: if (!flist_realloc(sess, &fl, &flsz, &flmax)) {
1.1 benno 537: ERRX1(sess, "flist_realloc");
538: goto out;
539: }
540:
541: ff = &fl[flsz - 1];
542: fflast = flsz > 1 ? &fl[flsz - 2] : NULL;
543:
544: /* Filename first. */
545:
1.4 deraadt 546: if (!flist_recv_name(sess, fd, ff, flag, last)) {
1.1 benno 547: ERRX1(sess, "flist_recv_name");
548: goto out;
549: }
550:
551: /* Read the file size. */
552:
1.4 deraadt 553: if (!io_read_ulong(sess, fd, &lval)) {
1.1 benno 554: ERRX1(sess, "io_read_ulong");
555: goto out;
556: }
557: ff->st.size = lval;
558:
559: /* Read the modification time. */
560:
1.4 deraadt 561: if (!(FLIST_TIME_SAME & flag)) {
562: if (!io_read_int(sess, fd, &ival)) {
1.1 benno 563: ERRX1(sess, "io_read_int");
564: goto out;
565: }
566: ff->st.mtime = ival;
1.5 deraadt 567: } else if (fflast == NULL) {
1.1 benno 568: ERRX(sess, "same time without last entry");
569: goto out;
570: } else
571: ff->st.mtime = fflast->st.mtime;
572:
573: /* Read the file mode. */
574:
1.4 deraadt 575: if (!(FLIST_MODE_SAME & flag)) {
576: if (!io_read_int(sess, fd, &ival)) {
1.1 benno 577: ERRX1(sess, "io_read_int");
578: goto out;
579: }
580: ff->st.mode = ival;
1.5 deraadt 581: } else if (fflast == NULL) {
1.1 benno 582: ERRX(sess, "same mode without last entry");
583: goto out;
584: } else
585: ff->st.mode = fflast->st.mode;
586:
1.6 ! benno 587: /* Conditional part: gid. */
! 588:
! 589: if (sess->opts->preserve_gids) {
! 590: if ( ! (FLIST_GID_SAME & flag)) {
! 591: if ( ! io_read_int(sess, fd, &ival)) {
! 592: ERRX1(sess, "io_read_int");
! 593: goto out;
! 594: }
! 595: ff->st.gid = ival;
! 596: } else if (NULL == fflast) {
! 597: ERRX(sess, "same gid "
! 598: "without last entry");
! 599: goto out;
! 600: } else
! 601: ff->st.gid = fflast->st.gid;
! 602: }
! 603:
! 604: /* Conditional part: link. */
1.1 benno 605:
606: if (S_ISLNK(ff->st.mode) &&
607: sess->opts->preserve_links) {
1.4 deraadt 608: if (!io_read_size(sess, fd, &lsz)) {
1.1 benno 609: ERRX1(sess, "io_read_size");
610: goto out;
1.5 deraadt 611: } else if (lsz == 0) {
1.1 benno 612: ERRX(sess, "empty link name");
613: goto out;
614: }
615: ff->link = calloc(lsz + 1, 1);
1.5 deraadt 616: if (ff->link == NULL) {
1.1 benno 617: ERR(sess, "calloc");
618: goto out;
619: }
1.4 deraadt 620: if (!io_read_buf(sess, fd, ff->link, lsz)) {
1.1 benno 621: ERRX1(sess, "io_read_buf");
622: goto out;
623: }
624: }
625:
626: LOG3(sess, "%s: received file metadata: "
627: "size %jd, mtime %jd, mode %o",
628: ff->path, (intmax_t)ff->st.size,
629: (intmax_t)ff->st.mtime, ff->st.mode);
630:
631: if (S_ISREG(ff->st.mode))
632: sess->total_size += ff->st.size;
633: }
634:
635: /* Remember to order the received list. */
636:
637: LOG2(sess, "received file metadata list: %zu", flsz);
638: qsort(fl, flsz, sizeof(struct flist), flist_cmp);
639: flist_topdirs(sess, fl, flsz);
640: *sz = flsz;
641: *flp = fl;
642: return 1;
643: out:
644: flist_free(fl, flsz);
645: *sz = 0;
646: *flp = NULL;
647: return 0;
648: }
649:
650: /*
651: * Generate a flist possibly-recursively given a file root, which may
652: * also be a regular file or symlink.
653: * On success, augments the generated list in "flp" of length "sz".
654: * Returns zero on failure, non-zero on success.
655: */
656: static int
1.3 benno 657: flist_gen_dirent(struct sess *sess, char *root, struct flist **fl, size_t *sz,
658: size_t *max)
1.1 benno 659: {
660: char *cargv[2], *cp;
661: int rc = 0;
662: FTS *fts;
663: FTSENT *ent;
664: struct flist *f;
665: size_t flsz = 0, stripdir;
666: struct stat st;
667:
668: cargv[0] = root;
669: cargv[1] = NULL;
670:
671: /*
672: * If we're a file, then revert to the same actions we use for
673: * the non-recursive scan.
674: */
675:
1.5 deraadt 676: if (lstat(root, &st) == -1) {
1.1 benno 677: ERR(sess, "%s: lstat", root);
678: return 0;
679: } else if (S_ISREG(st.st_mode)) {
1.4 deraadt 680: if (!flist_realloc(sess, fl, sz, max)) {
1.1 benno 681: ERRX1(sess, "flist_realloc");
682: return 0;
683: }
684: f = &(*fl)[(*sz) - 1];
1.5 deraadt 685: assert(f != NULL);
1.1 benno 686:
1.4 deraadt 687: if (!flist_append(sess, f, &st, root)) {
1.1 benno 688: ERRX1(sess, "flist_append");
689: return 0;
1.5 deraadt 690: } else if (unveil(root, "r") == -1) {
1.1 benno 691: ERR(sess, "%s: unveil", root);
692: return 0;
693: }
694: return 1;
695: } else if (S_ISLNK(st.st_mode)) {
1.4 deraadt 696: if (!sess->opts->preserve_links) {
1.1 benno 697: WARNX(sess, "%s: skipping symlink", root);
698: return 1;
1.4 deraadt 699: } else if (!flist_realloc(sess, fl, sz, max)) {
1.1 benno 700: ERRX1(sess, "flist_realloc");
701: return 0;
702: }
703: f = &(*fl)[(*sz) - 1];
1.5 deraadt 704: assert(f != NULL);
1.1 benno 705:
1.4 deraadt 706: if (!flist_append(sess, f, &st, root)) {
1.1 benno 707: ERRX1(sess, "flist_append");
708: return 0;
1.5 deraadt 709: } else if (unveil(root, "r") == -1) {
1.1 benno 710: ERR(sess, "%s: unveil", root);
711: return 0;
712: }
713: return 1;
1.4 deraadt 714: } else if (!S_ISDIR(st.st_mode)) {
1.1 benno 715: WARNX(sess, "%s: skipping special", root);
716: return 1;
717: }
718:
719: /*
720: * If we end with a slash, it means that we're not supposed to
721: * copy the directory part itself---only the contents.
722: * So set "stripdir" to be what we take out.
723: */
724:
725: stripdir = strlen(root);
726: assert(stripdir > 0);
1.5 deraadt 727: if (root[stripdir - 1] != '/')
1.1 benno 728: stripdir = 0;
729:
730: /*
731: * If we're not stripping anything, then see if we need to strip
732: * out the leading material in the path up to and including the
733: * last directory component.
734: */
735:
1.5 deraadt 736: if (stripdir == 0)
737: if ((cp = strrchr(root, '/')) != NULL)
1.1 benno 738: stripdir = cp - root + 1;
739:
740: /*
741: * If we're recursive, then we need to take down all of the
742: * files and directory components, so use fts(3).
743: * Copying the information file-by-file into the flstat.
744: * We'll make sense of it in flist_send.
745: */
746:
1.5 deraadt 747: if ((fts = fts_open(cargv, FTS_PHYSICAL, NULL)) == NULL) {
1.1 benno 748: ERR(sess, "fts_open");
749: return 0;
750: }
751:
752: errno = 0;
1.5 deraadt 753: while ((ent = fts_read(fts)) != NULL) {
1.4 deraadt 754: if (!flist_fts_check(sess, ent)) {
1.1 benno 755: errno = 0;
756: continue;
757: }
758:
759: /* We don't allow symlinks without -l. */
760:
1.5 deraadt 761: assert(ent->fts_statp != NULL);
1.1 benno 762: if (S_ISLNK(ent->fts_statp->st_mode) &&
1.4 deraadt 763: !sess->opts->preserve_links) {
1.1 benno 764: WARNX(sess, "%s: skipping "
765: "symlink", ent->fts_path);
766: continue;
767: }
768:
769: /* Allocate a new file entry. */
770:
1.4 deraadt 771: if (!flist_realloc(sess, fl, sz, max)) {
1.1 benno 772: ERRX1(sess, "flist_realloc");
773: goto out;
774: }
775: flsz++;
776: f = &(*fl)[*sz - 1];
777:
778: /* Our path defaults to "." for the root. */
779:
780: if ('\0' == ent->fts_path[stripdir]) {
781: if (asprintf(&f->path, "%s.", ent->fts_path) < 0) {
782: ERR(sess, "asprintf");
783: f->path = NULL;
784: goto out;
785: }
786: } else {
1.5 deraadt 787: if ((f->path = strdup(ent->fts_path)) == NULL) {
1.1 benno 788: ERR(sess, "strdup");
789: goto out;
790: }
791: }
792:
793: f->wpath = f->path + stripdir;
794: flist_copy_stat(f, ent->fts_statp);
795:
796: /* Optionally copy link information. */
797:
798: if (S_ISLNK(ent->fts_statp->st_mode)) {
799: f->link = symlink_read(sess, f->path);
1.5 deraadt 800: if (f->link == NULL) {
1.1 benno 801: ERRX1(sess, "symlink_read");
802: goto out;
803: }
804: }
805:
806: /* Reset errno for next fts_read() call. */
807: errno = 0;
808: }
809: if (errno) {
810: ERR(sess, "fts_read");
811: goto out;
1.5 deraadt 812: } else if (unveil(root, "r") == -1) {
1.1 benno 813: ERR(sess, "%s: unveil", root);
814: goto out;
815: }
816:
817: LOG3(sess, "generated %zu filenames: %s", flsz, root);
818: rc = 1;
819: out:
820: fts_close(fts);
821: return rc;
822: }
823:
824: /*
825: * Generate a flist recursively given the array of directories (or
826: * files, symlinks, doesn't matter) specified in argv (argc >0).
827: * On success, stores the generated list in "flp" with length "sz",
828: * which may be zero.
829: * Returns zero on failure, non-zero on success.
830: */
831: static int
1.3 benno 832: flist_gen_dirs(struct sess *sess, size_t argc, char **argv, struct flist **flp,
833: size_t *sz)
1.1 benno 834: {
835: size_t i, max = 0;
836:
837: for (i = 0; i < argc; i++)
1.4 deraadt 838: if (!flist_gen_dirent(sess, argv[i], flp, sz, &max))
1.1 benno 839: break;
840:
841: if (i == argc) {
842: LOG2(sess, "recursively generated %zu filenames", *sz);
843: return 1;
844: }
845:
846: ERRX1(sess, "flist_gen_dirent");
847: flist_free(*flp, max);
848: *flp = NULL;
849: *sz = 0;
850: return 0;
851: }
852:
853: /*
854: * Generate list of files from the command-line argc (>0) and argv.
855: * On success, stores the generated list in "flp" with length "sz",
856: * which may be zero.
857: * Returns zero on failure, non-zero on success.
858: */
859: static int
1.3 benno 860: flist_gen_files(struct sess *sess, size_t argc, char **argv,
861: struct flist **flp, size_t *sz)
1.1 benno 862: {
863: struct flist *fl = NULL, *f;
864: size_t i, flsz = 0;
865: struct stat st;
866:
867: assert(argc);
868:
1.5 deraadt 869: if ((fl = calloc(argc, sizeof(struct flist))) == NULL) {
1.1 benno 870: ERR(sess, "calloc");
871: return 0;
872: }
873:
874: for (i = 0; i < argc; i++) {
875: if ('\0' == argv[i][0])
876: continue;
1.5 deraadt 877: if (lstat(argv[i], &st) == -1) {
1.1 benno 878: ERR(sess, "%s: lstat", argv[i]);
879: goto out;
880: }
881:
882: /*
883: * File type checks.
884: * In non-recursive mode, we don't accept directories.
885: * We also skip symbolic links without -l.
886: * Beyond that, we only accept regular files.
887: */
888:
889: if (S_ISDIR(st.st_mode)) {
890: WARNX(sess, "%s: skipping directory", argv[i]);
891: continue;
892: } else if (S_ISLNK(st.st_mode)) {
1.4 deraadt 893: if (!sess->opts->preserve_links) {
1.1 benno 894: WARNX(sess, "%s: skipping "
895: "symlink", argv[i]);
896: continue;
897: }
1.4 deraadt 898: } else if (!S_ISREG(st.st_mode)) {
1.1 benno 899: WARNX(sess, "%s: skipping special", argv[i]);
900: continue;
901: }
902:
1.3 benno 903:
1.1 benno 904: f = &fl[flsz++];
1.5 deraadt 905: assert(f != NULL);
1.1 benno 906:
907: /* Add this file to our file-system worldview. */
908:
1.5 deraadt 909: if (unveil(argv[i], "r") == -1) {
1.1 benno 910: ERR(sess, "%s: unveil", argv[i]);
911: goto out;
1.4 deraadt 912: } else if (!flist_append(sess, f, &st, argv[i])) {
1.1 benno 913: ERRX1(sess, "flist_append");
914: goto out;
915: }
916: }
917:
918: LOG2(sess, "non-recursively generated %zu filenames", flsz);
919: *sz = flsz;
920: *flp = fl;
921: return 1;
922: out:
923: flist_free(fl, argc);
924: *sz = 0;
925: *flp = NULL;
926: return 0;
927: }
928:
929: /*
930: * Generate a sorted, de-duplicated list of file metadata.
931: * In non-recursive mode (the default), we use only the files we're
932: * given.
933: * Otherwise, directories are recursively examined.
934: * Returns zero on failure, non-zero on success.
935: * On success, "fl" will need to be freed with flist_free().
936: */
937: int
1.3 benno 938: flist_gen(struct sess *sess, size_t argc, char **argv, struct flist **flp,
939: size_t *sz)
1.1 benno 940: {
941: int rc;
942:
943: assert(argc > 0);
944: rc = sess->opts->recursive ?
945: flist_gen_dirs(sess, argc, argv, flp, sz) :
946: flist_gen_files(sess, argc, argv, flp, sz);
947:
948: /* After scanning, lock our file-system view. */
949:
1.5 deraadt 950: if (unveil(NULL, NULL) == -1) {
1.1 benno 951: ERR(sess, "unveil");
952: return 0;
1.4 deraadt 953: } else if (!rc)
1.1 benno 954: return 0;
955:
956: qsort(*flp, *sz, sizeof(struct flist), flist_cmp);
957:
958: if (flist_dedupe(sess, flp, sz)) {
959: flist_topdirs(sess, *flp, *sz);
960: return 1;
961: }
962:
963: ERRX1(sess, "flist_dedupe");
964: flist_free(*flp, *sz);
965: *flp = NULL;
966: *sz = 0;
967: return 0;
968: }
969:
970: /*
971: * Generate a list of files in root to delete that are within the
972: * top-level directories stipulated by "wfl".
973: * Only handles symbolic links, directories, and regular files.
974: * Returns zero on failure (fl and flsz will be NULL and zero), non-zero
975: * on success.
976: * On success, "fl" will need to be freed with flist_free().
977: */
978: int
1.3 benno 979: flist_gen_dels(struct sess *sess, const char *root, struct flist **fl,
980: size_t *sz, const struct flist *wfl, size_t wflsz)
1.1 benno 981: {
982: char **cargv = NULL;
983: int rc = 0, c;
984: FTS *fts = NULL;
985: FTSENT *ent;
986: struct flist *f;
987: size_t cargvs = 0, i, j, max = 0, stripdir;
988: ENTRY hent;
989: ENTRY *hentp;
1.2 benno 990:
1.1 benno 991: *fl = NULL;
992: *sz = 0;
993:
994: /* Only run this code when we're recursive. */
995:
1.4 deraadt 996: if (!sess->opts->recursive)
1.1 benno 997: return 1;
998:
1.2 benno 999: /*
1.1 benno 1000: * Gather up all top-level directories for scanning.
1001: * This is stipulated by rsync's --delete behaviour, where we
1002: * only delete things in the top-level directories given on the
1003: * command line.
1004: */
1005:
1006: assert(wflsz > 0);
1007: for (i = 0; i < wflsz; i++)
1008: if (FLSTAT_TOP_DIR & wfl[i].st.flags)
1009: cargvs++;
1.5 deraadt 1010: if (cargvs == 0)
1.1 benno 1011: return 1;
1012:
1.5 deraadt 1013: if ((cargv = calloc(cargvs + 1, sizeof(char *))) == NULL) {
1.1 benno 1014: ERR(sess, "calloc");
1015: return 0;
1016: }
1017:
1018: /*
1019: * If we're given just a "." as the first entry, that means
1020: * we're doing a relative copy with a trailing slash.
1021: * Special-case this just for the sake of simplicity.
1022: * Otherwise, look through all top-levels.
1023: */
1024:
1.5 deraadt 1025: if (wflsz && strcmp(wfl[0].wpath, ".") == 0) {
1026: assert(cargvs == 1);
1.1 benno 1027: assert(S_ISDIR(wfl[0].st.mode));
1028: if (asprintf(&cargv[0], "%s/", root) < 0) {
1029: ERR(sess, "asprintf");
1030: cargv[0] = NULL;
1031: goto out;
1032: }
1033: cargv[1] = NULL;
1034: } else {
1035: for (i = j = 0; i < wflsz; i++) {
1.4 deraadt 1036: if (!(FLSTAT_TOP_DIR & wfl[i].st.flags))
1.1 benno 1037: continue;
1038: assert(S_ISDIR(wfl[i].st.mode));
1039: assert(strcmp(wfl[i].wpath, "."));
1.5 deraadt 1040: c = asprintf(&cargv[j], "%s/%s", root, wfl[i].wpath);
1.1 benno 1041: if (c < 0) {
1042: ERR(sess, "asprintf");
1043: cargv[j] = NULL;
1044: goto out;
1045: }
1046: LOG4(sess, "%s: will scan "
1047: "for deletions", cargv[j]);
1048: j++;
1049: }
1050: assert(j == cargvs);
1051: cargv[j] = NULL;
1052: }
1053:
1054: LOG2(sess, "delete from %zu directories", cargvs);
1055:
1056: /*
1057: * Next, use the standard hcreate(3) hashtable interface to hash
1058: * all of the files that we want to synchronise.
1059: * This way, we'll be able to determine which files we want to
1060: * delete in O(n) time instead of O(n * search) time.
1061: * Plus, we can do the scan in-band and only allocate the files
1062: * we want to delete.
1063: */
1064:
1.4 deraadt 1065: if (!hcreate(wflsz)) {
1.1 benno 1066: ERR(sess, "hcreate");
1067: goto out;
1068: }
1069:
1070: for (i = 0; i < wflsz; i++) {
1071: memset(&hent, 0, sizeof(ENTRY));
1.5 deraadt 1072: if ((hent.key = strdup(wfl[i].wpath)) == NULL) {
1.1 benno 1073: ERR(sess, "strdup");
1074: goto out;
1075: }
1.5 deraadt 1076: if ((hentp = hsearch(hent, ENTER)) == NULL) {
1.1 benno 1077: ERR(sess, "hsearch");
1078: goto out;
1079: } else if (hentp->key != hent.key) {
1080: ERRX(sess, "%s: duplicate", wfl[i].wpath);
1081: free(hent.key);
1082: goto out;
1083: }
1084: }
1085:
1.2 benno 1086: /*
1.1 benno 1087: * Now we're going to try to descend into all of the top-level
1088: * directories stipulated by the file list.
1089: * If the directories don't exist, it's ok.
1090: */
1091:
1.5 deraadt 1092: if ((fts = fts_open(cargv, FTS_PHYSICAL, NULL)) == NULL) {
1.1 benno 1093: ERR(sess, "fts_open");
1094: goto out;
1095: }
1096:
1097: stripdir = strlen(root) + 1;
1098: errno = 0;
1.5 deraadt 1099: while ((ent = fts_read(fts)) != NULL) {
1100: if (ent->fts_info == FTS_NS)
1.1 benno 1101: continue;
1.4 deraadt 1102: if (!flist_fts_check(sess, ent)) {
1.1 benno 1103: errno = 0;
1104: continue;
1105: } else if (stripdir >= ent->fts_pathlen)
1106: continue;
1107:
1108: /* Look up in hashtable. */
1109:
1110: memset(&hent, 0, sizeof(ENTRY));
1111: hent.key = ent->fts_path + stripdir;
1.5 deraadt 1112: if (hsearch(hent, FIND) != NULL)
1.1 benno 1113: continue;
1114:
1115: /* Not found: we'll delete it. */
1116:
1.4 deraadt 1117: if (!flist_realloc(sess, fl, sz, &max)) {
1.1 benno 1118: ERRX1(sess, "flist_realloc");
1119: goto out;
1120: }
1121: f = &(*fl)[*sz - 1];
1122:
1.5 deraadt 1123: if ((f->path = strdup(ent->fts_path)) == NULL) {
1.1 benno 1124: ERR(sess, "strdup");
1125: goto out;
1126: }
1127: f->wpath = f->path + stripdir;
1.5 deraadt 1128: assert(ent->fts_statp != NULL);
1.1 benno 1129: flist_copy_stat(f, ent->fts_statp);
1130: errno = 0;
1131: }
1132:
1133: if (errno) {
1134: ERR(sess, "fts_read");
1135: goto out;
1136: }
1137:
1138: qsort(*fl, *sz, sizeof(struct flist), flist_cmp);
1139: rc = 1;
1140: out:
1.5 deraadt 1141: if (fts != NULL)
1.1 benno 1142: fts_close(fts);
1143: for (i = 0; i < cargvs; i++)
1144: free(cargv[i]);
1145: free(cargv);
1146: hdestroy();
1147: return rc;
1148: }
1149:
1150: /*
1151: * Delete all files and directories in "fl".
1152: * If called with a zero-length "fl", does nothing.
1153: * If dry_run is specified, simply write what would be done.
1154: * Return zero on failure, non-zero on success.
1155: */
1156: int
1.3 benno 1157: flist_del(struct sess *sess, int root, const struct flist *fl, size_t flsz)
1.1 benno 1158: {
1159: ssize_t i;
1160: int flag;
1161:
1.5 deraadt 1162: if (flsz == 0)
1.1 benno 1163: return 1;
1164:
1165: assert(sess->opts->del);
1166: assert(sess->opts->recursive);
1167:
1168: for (i = flsz - 1; i >= 0; i--) {
1169: LOG1(sess, "%s: deleting", fl[i].wpath);
1170: if (sess->opts->dry_run)
1171: continue;
1.5 deraadt 1172: assert(root != -1);
1.1 benno 1173: flag = S_ISDIR(fl[i].st.mode) ? AT_REMOVEDIR : 0;
1.5 deraadt 1174: if (unlinkat(root, fl[i].wpath, flag) == -1 &&
1175: errno != ENOENT) {
1.1 benno 1176: ERR(sess, "%s: unlinkat", fl[i].wpath);
1177: return 0;
1178: }
1179: }
1180:
1181: return 1;
1182: }