Hello again, Job
Sorry for the recurring formatting and tab issues.
Here's the updated diff.

Index: extern.h
===================================================================
RCS file: /cvs/src/usr.bin/rsync/extern.h,v
retrieving revision 1.44
diff -u -p -u -p -r1.44 extern.h
--- extern.h    2 Aug 2022 18:09:20 -0000       1.44
+++ extern.h    22 Feb 2023 17:48:04 -0000
@@ -134,6 +134,7 @@ struct      opts {
        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 */
Index: flist.c
===================================================================
RCS file: /cvs/src/usr.bin/rsync/flist.c,v
retrieving revision 1.37
diff -u -p -u -p -r1.37 flist.c
--- flist.c     26 Dec 2022 19:16:02 -0000      1.37
+++ flist.c     22 Feb 2023 17:48:05 -0000
@@ -802,10 +802,11 @@ static int
flist_gen_dirent(struct sess *sess, char *root, struct flist **fl, size_t *sz,
     size_t *max)
 {
-       char            *cargv[2], *cp;
-       int              rc = 0, flag;
-       FTS             *fts;
-       FTSENT          *ent;
+       char    *cargv[2], *prune_cargv[2], *cp;
+       int             rc = 0, flag, empty_chain;
+       FTS             *fts, *prunefts;
+       FTSENT  *ent, *prunent;
+
        struct flist    *f;
        size_t           i, flsz = 0, nxdev = 0, stripdir;
        dev_t           *newxdev, *xdev = NULL;
@@ -905,6 +906,35 @@ flist_gen_dirent(struct sess *sess, char
                if (!flist_fts_check(sess, ent)) {
                        errno = 0;
                        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) {
+                               prune_cargv[0] = ent->fts_name;
+                               prune_cargv[1] = NULL;
+                               if ((prunefts = fts_open(prune_cargv,
+                                                                               
 FTS_PHYSICAL, NULL)) == NULL) {
+                               ERR("fts_open");
+                               return 0;
+                       }
+                       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. */
Index: main.c
===================================================================
RCS file: /cvs/src/usr.bin/rsync/main.c,v
retrieving revision 1.66
diff -u -p -u -p -r1.66 main.c
--- main.c      14 Feb 2023 17:15:15 -0000      1.66
+++ main.c      22 Feb 2023 17:48:05 -0000
@@ -326,6 +326,7 @@ const struct option  lopts[] = {
     { "perms",               no_argument,    &opts.preserve_perms,       1 },
     { "no-perms",    no_argument,    &opts.preserve_perms,       0 },
     { "port",                required_argument, NULL,                OP_PORT },
+       { "prune-empty-dirs", no_argument, &opts.prune_empty_dirs, 1 },
     { "recursive",   no_argument,    &opts.recursive,    1 },
     { "no-recursive",        no_argument,    &opts.recursive,    0 },
     { "rsh",         required_argument, NULL,                'e' },
@@ -362,7 +363,7 @@ main(int argc, char *argv[])

        opts.max_size = opts.min_size = -1;

-       while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvxz", lopts, &lidx))
+       while ((c = getopt_long(argc, argv, "Dae:ghlmnoprtvxz", lopts, &lidx))
            != -1) {
                switch (c) {
                case 'D':
@@ -388,6 +389,9 @@ main(int argc, char *argv[])
                case 'l':
                        opts.preserve_links = 1;
                        break;
+               case 'm':
+                       opts.prune_empty_dirs = 1;
+                       break;
                case 'n':
                        opts.dry_run = 1;
                        break;
@@ -633,7 +637,7 @@ basedir:
        exit(rc);
 usage:
        fprintf(stderr, "usage: %s"
-           " [-aDglnoprtvx] [-e program] [--address=sourceaddr]\n"
+           " [-aDglmnoprtvx] [-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"
Index: rsync.1
===================================================================
RCS file: /cvs/src/usr.bin/rsync/rsync.1,v
retrieving revision 1.30
diff -u -p -u -p -r1.30 rsync.1
--- rsync.1     2 Aug 2022 18:09:20 -0000       1.30
+++ rsync.1     22 Feb 2023 17:48:05 -0000
@@ -150,6 +150,8 @@ bytes.
 See
 .Fl -max-size
 on the definition of size.
+.It Fl m , -prune-empty-dirs
+Prune empty directory chains from the file list.
 .It Fl n , -dry-run
 Do not actually modify the destination.
 Mainly useful in combination with

Reply via email to