Hello, This patch adds the -m/--prume-empty-dirs option to openrsync while keeping said feature compatible with rsync this avoids the 27 -> 31 protocol mismatch error by not sharing the -m option to remote This was tested locally (openrsync -> openrsync) and remotely (openrsync -> rsync) Sorry if any mistakes were made
diff -ura ../origsync/extern.h ./extern.h --- ../origsync/extern.h 2023-02-21 21:43:18.871417908 +0100 +++ ./extern.h 2023-02-21 18:26:12.176316267 +0100 @@ -134,6 +134,7 @@ int server; /* --server */ int recursive; /* -r */ int dry_run; /* -n */ + int prune_empty_dirs; /* -m */ int preserve_times; /* -t */ int preserve_perms; /* -p */ int preserve_links; /* -l */ diff -ura ../origsync/flist.c ./flist.c --- ../origsync/flist.c 2023-02-21 21:43:07.778145448 +0100 +++ ./flist.c 2023-02-22 06:09:51.097975517 +0100 @@ -907,6 +907,36 @@ continue; } + /* + * If -m (prune empty dirs) is enabled, create a new fts + * to independently traverse directories at once and determine + * whether we are dealing with a hierarchy of empty + * directories, if so, skip. + */ + + if (sess->opts->prune_empty_dirs && ent->fts_info == FTS_D){ + char *prune_cargv[2]; + prune_cargv[0] = ent->fts_name; + prune_cargv[1] = NULL; + FTS *prunefts; + if ((prunefts = fts_open(prune_cargv, FTS_PHYSICAL, NULL)) == NULL) { + ERR("fts_open"); + return 0; + } + FTSENT *prunent; + int empty_chain = 1; + while ((prunent = fts_read(prunefts)) != NULL) { + if (prunent->fts_info != FTS_D && prunent->fts_info != FTS_DP){ + empty_chain = 0; + break; + } + } + if (empty_chain){ + continue; + } + fts_close(prunefts); + } + /* We don't allow symlinks without -l. */ assert(ent->fts_statp != NULL); diff -ura ../origsync/main.c ./main.c --- ../origsync/main.c 2023-02-21 21:43:10.861461862 +0100 +++ ./main.c 2023-02-22 05:21:15.047310523 +0100 @@ -340,6 +340,7 @@ { "verbose", no_argument, &verbose, 1 }, { "no-verbose", no_argument, &verbose, 0 }, { "version", no_argument, NULL, OP_VERSION }, + { "prune-empty-dirs", no_argument, &opts.prune_empty_dirs, 1 }, { NULL, 0, NULL, 0 } }; @@ -362,7 +363,7 @@ opts.max_size = opts.min_size = -1; - while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvxz", lopts, &lidx)) + while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvxzm", lopts, &lidx)) != -1) { switch (c) { case 'D': @@ -382,6 +383,9 @@ case 'e': opts.ssh_prog = optarg; break; + case 'm': + opts.prune_empty_dirs = 1; + break; case 'g': opts.preserve_gids = 1; break; @@ -633,7 +637,7 @@ exit(rc); usage: fprintf(stderr, "usage: %s" - " [-aDglnoprtvx] [-e program] [--address=sourceaddr]\n" + " [-aDglnoprtvxm] [-e program] [--address=sourceaddr]\n" "\t[--contimeout=seconds] [--compare-dest=dir] [--del] [--exclude]\n" "\t[--exclude-from=file] [--include] [--include-from=file]\n" "\t[--no-motd] [--numeric-ids] [--port=portnumber]\n" diff -ura ../origsync/rsync.1 ./rsync.1 --- ../origsync/rsync.1 2023-02-21 21:43:19.451414725 +0100 +++ ./rsync.1 2023-02-22 05:45:26.459345977 +0100 @@ -220,6 +220,8 @@ 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 m , -prune-empty-dirs +Prune empty directory chains from the file list. .It Fl -version Print version and exit. .El