diff options
author | bket <bket@cvs.openbsd.org> | 2019-04-04 04:19:55 +0000 |
---|---|---|
committer | bket <bket@cvs.openbsd.org> | 2019-04-04 04:19:55 +0000 |
commit | 378cd07b6358ce26d9787f640e067db143afbab9 (patch) | |
tree | 24a7edea91ddbdd72e11443ec85cd0abaf91ef7e /usr.bin/rsync | |
parent | ac781e5d0070a5fccc462e858dafaf804c3a46fa (diff) |
Add support for not crossing filesystem boundaries (-x) to rsync. Option
and behaviour is the same as GPL rsync.
Initial diff received feedback from benno@, schwarze@, deraadt@ and
florian@. Thanks!
OK deraadt@
Diffstat (limited to 'usr.bin/rsync')
-rw-r--r-- | usr.bin/rsync/extern.h | 3 | ||||
-rw-r--r-- | usr.bin/rsync/fargs.c | 6 | ||||
-rw-r--r-- | usr.bin/rsync/flist.c | 78 | ||||
-rw-r--r-- | usr.bin/rsync/main.c | 9 | ||||
-rw-r--r-- | usr.bin/rsync/rsync.1 | 11 |
5 files changed, 95 insertions, 12 deletions
diff --git a/usr.bin/rsync/extern.h b/usr.bin/rsync/extern.h index 9ae08e7515e..305821be579 100644 --- a/usr.bin/rsync/extern.h +++ b/usr.bin/rsync/extern.h @@ -1,4 +1,4 @@ -/* $Id: extern.h,v 1.27 2019/04/02 05:32:08 deraadt Exp $ */ +/* $Id: extern.h,v 1.28 2019/04/04 04:19:54 bket Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -117,6 +117,7 @@ struct opts { int devices; /* --devices */ int specials; /* --specials */ int numeric_ids; /* --numeric-ids */ + int one_file_system; /* -x */ char *rsync_path; /* --rsync-path */ char *ssh_prog; /* --rsh or -e */ char *port; /* --port */ diff --git a/usr.bin/rsync/fargs.c b/usr.bin/rsync/fargs.c index 55bf1b4b8af..59dadc856c7 100644 --- a/usr.bin/rsync/fargs.c +++ b/usr.bin/rsync/fargs.c @@ -1,4 +1,4 @@ -/* $Id: fargs.c,v 1.15 2019/04/02 05:32:08 deraadt Exp $ */ +/* $Id: fargs.c,v 1.16 2019/04/04 04:19:54 bket Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -106,6 +106,10 @@ fargs_cmdline(struct sess *sess, const struct fargs *f, size_t *skip) addargs(&args, "-v"); if (sess->opts->verbose > 0) addargs(&args, "-v"); + if (sess->opts->one_file_system > 1) + addargs(&args, "-x"); + if (sess->opts->one_file_system > 0) + addargs(&args, "-x"); if (sess->opts->specials && !sess->opts->devices) addargs(&args, "--specials"); if (!sess->opts->specials && sess->opts->devices) diff --git a/usr.bin/rsync/flist.c b/usr.bin/rsync/flist.c index b39599583e3..ac29ad47098 100644 --- a/usr.bin/rsync/flist.c +++ b/usr.bin/rsync/flist.c @@ -1,4 +1,4 @@ -/* $Id: flist.c,v 1.23 2019/03/31 09:26:05 deraadt Exp $ */ +/* $Id: flist.c,v 1.24 2019/04/04 04:19:54 bket Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2019 Florian Obser <florian@openbsd.org> @@ -804,11 +804,12 @@ flist_gen_dirent(struct sess *sess, char *root, struct flist **fl, size_t *sz, size_t *max) { char *cargv[2], *cp; - int rc = 0; + int rc = 0, nxdev = 0, flag, i; FTS *fts; FTSENT *ent; struct flist *f; size_t flsz = 0, stripdir; + dev_t *xdev; struct stat st; cargv[0] = root; @@ -913,6 +914,48 @@ flist_gen_dirent(struct sess *sess, char *root, struct flist **fl, size_t *sz, continue; } + /* + * If rsync is told to avoid crossing a filesystem + * boundary when recursing, then replace all mount point + * directories with empty directories. The latter is + * prevented by telling rsync multiple times to avoid + * crossing a filesystem boundary when recursing. + * Replacing mount point directories is tricky. We need + * to sort out which directories to include. As such, + * keep track of unique device inodes, and use these for + * comparison. + */ + + if (sess->opts->one_file_system && + ent->fts_statp->st_dev != st.st_dev) { + if (sess->opts->one_file_system > 1 || + !S_ISDIR(ent->fts_statp->st_mode)) + continue; + + if ((xdev = malloc(sizeof(dev_t))) == NULL) { + ERRX1(sess, "malloc"); + goto out; + } + + flag = 0; + for (i = 0; i < nxdev; i++) + if (xdev[i] == ent->fts_statp->st_dev) { + flag = 1; + break; + } + if (flag) + continue; + + if (nxdev) + if ((xdev = realloc(xdev, sizeof(dev_t))) == + NULL) { + ERRX1(sess, "realloc"); + goto out; + } + xdev[nxdev] = ent->fts_statp->st_dev; + nxdev++; + } + /* Allocate a new file entry. */ if (!flist_realloc(sess, fl, sz, max)) { @@ -966,6 +1009,8 @@ flist_gen_dirent(struct sess *sess, char *root, struct flist **fl, size_t *sz, rc = 1; out: fts_close(fts); + if (sess->opts->one_file_system) + free(xdev); return rc; } @@ -1129,10 +1174,11 @@ flist_gen_dels(struct sess *sess, const char *root, struct flist **fl, size_t *sz, const struct flist *wfl, size_t wflsz) { char **cargv = NULL; - int rc = 0, c; + int rc = 0, c, flag; FTS *fts = NULL; FTSENT *ent; struct flist *f; + struct stat st; size_t cargvs = 0, i, j, max = 0, stripdir; ENTRY hent; ENTRY *hentp; @@ -1253,6 +1299,31 @@ flist_gen_dels(struct sess *sess, const char *root, struct flist **fl, } else if (stripdir >= ent->fts_pathlen) continue; + assert(ent->fts_statp != NULL); + + /* + * If rsync is told to avoid crossing a filesystem + * boundary when recursing, then exclude all entries + * from the list with a device inode, which does not + * match that of one of the top-level directories. + */ + + if (sess->opts->one_file_system) { + flag = 0; + for (i = 0; i < wflsz; i++) { + if (stat(wfl[i].path, &st) == -1) { + ERR(sess, "%s: stat", wfl[i].path); + goto out; + } + if (ent->fts_statp->st_dev == st.st_dev) { + flag = 1; + break; + } + } + if (!flag) + continue; + } + /* Look up in hashtable. */ memset(&hent, 0, sizeof(ENTRY)); @@ -1273,7 +1344,6 @@ flist_gen_dels(struct sess *sess, const char *root, struct flist **fl, goto out; } f->wpath = f->path + stripdir; - assert(ent->fts_statp != NULL); flist_copy_stat(f, ent->fts_statp); errno = 0; } diff --git a/usr.bin/rsync/main.c b/usr.bin/rsync/main.c index dd598d93eb2..4f0b386e0bf 100644 --- a/usr.bin/rsync/main.c +++ b/usr.bin/rsync/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.43 2019/04/01 13:04:51 schwarze Exp $ */ +/* $Id: main.c,v 1.44 2019/04/04 04:19:54 bket Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -315,7 +315,7 @@ main(int argc, char *argv[]) memset(&opts, 0, sizeof(struct opts)); - while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvz", lopts, NULL)) + while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvxz", lopts, NULL)) != -1) { switch (c) { case 'D': @@ -359,6 +359,9 @@ main(int argc, char *argv[]) case 'v': opts.verbose++; break; + case 'x': + opts.one_file_system++; + break; case 'z': fprintf(stderr, "%s: -z not supported yet\n", getprogname()); break; @@ -505,7 +508,7 @@ main(int argc, char *argv[]) exit(rc); usage: fprintf(stderr, "usage: %s" - " [-aDglnoprtv] [-e program] [--del] [--numeric-ids]\n" + " [-aDglnoprtvx] [-e program] [--del] [--numeric-ids]\n" "\t[--port=portnumber] [--rsync-path=program] [--version]\n" "\tsource ... directory\n", getprogname()); diff --git a/usr.bin/rsync/rsync.1 b/usr.bin/rsync/rsync.1 index c16168fff8f..3747a3fe70e 100644 --- a/usr.bin/rsync/rsync.1 +++ b/usr.bin/rsync/rsync.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rsync.1,v 1.16 2019/04/01 13:04:51 schwarze Exp $ +.\" $OpenBSD: rsync.1,v 1.17 2019/04/04 04:19:54 bket Exp $ .\" .\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: April 1 2019 $ +.Dd $Mdocdate: April 4 2019 $ .Dt OPENRSYNC 1 .Os .Sh NAME @@ -22,7 +22,7 @@ .Nd synchronise local and remote files .Sh SYNOPSIS .Nm openrsync -.Op Fl aDglnoprtv +.Op Fl aDglnoprtvx .Op Fl e Ar program .Op Fl -del .Op Fl -numeric-ids @@ -141,6 +141,11 @@ Increase verbosity. Specify once for files being transferred, twice for specific status, thrice for per-file transfer information, and four times for per-file breakdowns. +.It Fl x +Do not cross filesystem boundaries. +If this option is repeated, all mount point directories from the copy are +omitted. +Otherwise, it includes an empty directory at each mount point it encounters. .It Fl -version Print version and exit. .El |