This does not do the right thing when sender and receiver do not agree
on file system boundaries.
Consider these mount points
/dev/sd1g on /rsync-test/dst type ffs (local)
/dev/sd1e on /rsync-test/src/e type ffs (local)
/dev/sd1f on /rsync-test/src/e/f type ffs (local)
and these files / directories:
drwxr-xr-x 3 root wheel 512 Apr 2 10:39 src
drwxr-xr-x 3 root wheel 512 Apr 2 10:39 src/e
-rw-r--r-- 1 root wheel 0 Apr 2 10:39 src/e/e-foo
drwxr-xr-x 2 root wheel 512 Apr 2 10:39 src/e/f
-rw-r--r-- 1 root wheel 0 Apr 2 10:39 src/e/f/f-foo
drwxr-xr-x 3 root wheel 512 Apr 2 10:38 dst
drwxr-xr-x 3 root wheel 512 Apr 2 10:54 dst/e
drwxr-xr-x 2 root wheel 512 Apr 2 10:54 dst/e/f
-rw-r--r-- 1 root wheel 0 Apr 2 10:54 dst/e/f/foo
$ rsync --delete -ax src/e/ dst/e/
results in
drwxr-xr-x 3 root wheel 512 Apr 2 10:38 dst
drwxr-xr-x 3 root wheel 512 Apr 2 10:39 dst/e
-rw-r--r-- 1 root wheel 0 Apr 2 10:39 dst/e/e-foo
drwxr-xr-x 2 root wheel 512 Apr 2 10:39 dst/e/f
-rw-r--r-- 1 root wheel 0 Apr 2 10:54 dst/e/f/foo
$ openrsync --rsync-path=/usr/bin/openrsync --delete -ax src/e/ dst/e/
results in
drwxr-xr-x 3 root wheel 512 Apr 2 10:38 dst
drwxr-xr-x 3 root wheel 512 Apr 2 10:39 dst/e
-rw-r--r-- 1 root wheel 0 Apr 2 10:39 dst/e/e-foo
drwxr-xr-x 2 root wheel 512 Apr 2 10:39 dst/e/f
note how it decended into dst/e/f and deleted foo
On Mon, Apr 01, 2019 at 09:36:34PM +0200, Björn Ketelaars wrote:
> Add --one-file-system, which prevents openrsync to cross filesystem
> boundaries. Option and behaviour is the same as GPL rsync.
>
> OK?
>
>
> diff --git usr.bin/rsync/extern.h usr.bin/rsync/extern.h
> index 12aceae566c..602cd24cede 100644
> --- usr.bin/rsync/extern.h
> +++ usr.bin/rsync/extern.h
> @@ -117,6 +117,7 @@ struct opts {
> int devices; /* --devices */
> int specials; /* --specials */
> int numeric_ids; /* --numeric-ids */
> + int one_file_system; /* --one-file-system or -x */
> char *rsync_path; /* --rsync-path */
> char *ssh_prog; /* --rsh or -e */
> char *port; /* --port */
> diff --git usr.bin/rsync/flist.c usr.bin/rsync/flist.c
> index b39599583e3..7f18966d85d 100644
> --- usr.bin/rsync/flist.c
> +++ usr.bin/rsync/flist.c
> @@ -804,7 +804,7 @@ 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, xdev = 0;
> FTS *fts;
> FTSENT *ent;
> struct flist *f;
> @@ -890,9 +890,15 @@ flist_gen_dirent(struct sess *sess, char *root, struct
> flist **fl, size_t *sz,
> * files and directory components, so use fts(3).
> * Copying the information file-by-file into the flstat.
> * We'll make sense of it in flist_send.
> + * If one-file-system is used, prevent fts(3) from descending
> + * into directories that have a different device number than
> + * the file from which the descent began.
> */
>
> - if ((fts = fts_open(cargv, FTS_PHYSICAL, NULL)) == NULL) {
> + if (sess->opts->one_file_system)
> + xdev = FTS_XDEV;
> +
> + if ((fts = fts_open(cargv, FTS_PHYSICAL | xdev, NULL)) == NULL) {
> ERR(sess, "fts_open");
> return 0;
> }
> @@ -1129,7 +1135,7 @@ 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, xdev = 0;
> FTS *fts = NULL;
> FTSENT *ent;
> struct flist *f;
> @@ -1235,9 +1241,15 @@ flist_gen_dels(struct sess *sess, const char *root,
> struct flist **fl,
> * Now we're going to try to descend into all of the top-level
> * directories stipulated by the file list.
> * If the directories don't exist, it's ok.
> + * If one-file-system is used, prevent fts(3) from descending
> + * into directories that have a different device number than
> + * the file from which the descent began.
> */
>
> - if ((fts = fts_open(cargv, FTS_PHYSICAL, NULL)) == NULL) {
> + if (sess->opts->one_file_system)
> + xdev = FTS_XDEV;
> +
> + if ((fts = fts_open(cargv, FTS_PHYSICAL | xdev, NULL)) == NULL) {
> ERR(sess, "fts_open");
> goto out;
> }
> diff --git usr.bin/rsync/main.c usr.bin/rsync/main.c
> index dd598d93eb2..3dbf6dd6028 100644
> --- usr.bin/rsync/main.c
> +++ usr.bin/rsync/main.c
> @@ -305,6 +305,7 @@ main(int argc, char *argv[])
> { "no-times", no_argument, &opts.preserve_times, 0 },
> { "verbose", no_argument, &opts.verbose, 1 },
> { "no-verbose", no_argument, &opts.verbose, 0 },
> + { "one-file-system", no_argument, NULL, 'x' },
> { NULL, 0, NULL, 0 }};
>
> /* Global pledge. */
> @@ -315,7 +316,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 +360,9 @@ main(int argc, char *argv[])
> case 'v':
> opts.verbose++;
> break;
> + case 'x':
> + opts.one_file_system = 1;
> + break;
> case 'z':
> fprintf(stderr, "%s: -z not supported yet\n",
> getprogname());
> break;
> diff --git usr.bin/rsync/rsync.1 usr.bin/rsync/rsync.1
> index c16168fff8f..911c848da7e 100644
> --- usr.bin/rsync/rsync.1
> +++ usr.bin/rsync/rsync.1
> @@ -141,6 +141,8 @@ 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 , -one-file-system
> +Do not cross filesystem boundaries.
> .It Fl -version
> Print version and exit.
> .El
>
--
I'm not entirely sure you are real.