More OS X patch tweaks.
authorWayne Davison <wayned@samba.org>
Sat, 26 Mar 2011 21:22:46 +0000 (14:22 -0700)
committerWayne Davison <wayned@samba.org>
Sat, 26 Mar 2011 21:22:46 +0000 (14:22 -0700)
fileflags.diff
hfs-compression.diff

index c1a2984f981338a0c1958a41964665e2974536df..9288aebacf216d312d0505eaea1cf9dd8b70ca2d 100644 (file)
@@ -8,7 +8,7 @@ To use this patch, run these commands for a successful build:
     ./configure
     make
 
-based-on: d52aeae4e9af689aed4ae6af2b7602552c1383e7
+based-on: 98ec67d7860209c5cbbc848769f2ba1a7062ddef
 diff --git a/Makefile.in b/Makefile.in
 --- a/Makefile.in
 +++ b/Makefile.in
@@ -66,7 +66,7 @@ diff --git a/compat.c b/compat.c
 diff --git a/configure.ac b/configure.ac
 --- a/configure.ac
 +++ b/configure.ac
-@@ -589,7 +589,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
+@@ -591,7 +591,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
      setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
      seteuid strerror putenv iconv_open locale_charset nl_langinfo getxattr \
      extattr_get_link sigaction sigprocmask setattrlist getgrouplist \
@@ -258,7 +258,7 @@ diff --git a/generator.c b/generator.c
  #ifdef SUPPORT_ACLS
                if (preserve_acls && !S_ISLNK(file->mode)) {
                        if (!ACL_READY(*sxp))
-@@ -1320,6 +1331,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1322,6 +1333,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        file->mode = dest_mode(file->mode, sx.st.st_mode,
                                               dflt_perms, statret == 0);
                }
@@ -269,7 +269,7 @@ diff --git a/generator.c b/generator.c
                if (statret != 0 && basis_dir[0] != NULL) {
                        int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
                                              itemizing, code);
-@@ -1362,10 +1377,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1357,10 +1372,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                /* We need to ensure that the dirs in the transfer have writable
                 * permissions during the time we are putting files within them.
                 * This is then fixed after the transfer is done. */
@@ -286,7 +286,7 @@ diff --git a/generator.c b/generator.c
                                rsyserr(FERROR_XFER, errno,
                                        "failed to modify permissions on %s",
                                        full_fname(fname));
-@@ -1400,6 +1420,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1403,6 +1423,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms,
                                       exists);
        }
@@ -297,7 +297,7 @@ diff --git a/generator.c b/generator.c
  
  #ifdef SUPPORT_HARD_LINKS
        if (preserve_hard_links && F_HLINK_NOT_FIRST(file)
-@@ -1979,13 +2003,17 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
+@@ -1982,13 +2006,17 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
                        continue;
                fname = f_name(file, NULL);
                if (fix_dir_perms)
@@ -329,6 +329,42 @@ diff --git a/log.c b/log.c
                        c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
                        c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
                        c[11] = '\0';
+diff --git a/main.c b/main.c
+--- a/main.c
++++ b/main.c
+@@ -26,6 +26,9 @@
+ #if defined CONFIG_LOCALE && defined HAVE_LOCALE_H
+ #include <locale.h>
+ #endif
++#ifdef SUPPORT_FORCE_CHANGE
++#include <sys/sysctl.h>
++#endif
+ extern int dry_run;
+ extern int list_only;
+@@ -834,6 +837,22 @@ static int do_recv(int f_in, int f_out, char *local_name)
+        * points to an identical file won't be replaced by the referent. */
+       copy_links = copy_dirlinks = copy_unsafe_links = 0;
++#ifdef SUPPORT_FORCE_CHANGE
++      if (force_change & SYS_IMMUTABLE) {
++              /* Determine whether we'll be able to unlock a system immutable item. */
++              int mib[2];
++              int securityLevel = 0;
++              size_t len = sizeof securityLevel;
++
++              mib[0] = CTL_KERN;
++              mib[1] = KERN_SECURELVL;
++              if (sysctl(mib, 2, &securityLevel, &len, NULL, 0) == 0 && securityLevel > 0) {
++                      rprintf(FERROR, "System security level is too high to force mutability on system immutable files and directories.\n");
++                      exit_cleanup(RERR_UNSUPPORTED);
++              }
++      }
++#endif
++
+ #ifdef SUPPORT_HARD_LINKS
+       if (preserve_hard_links && !inc_recurse)
+               match_hard_links(first_flist);
 diff --git a/options.c b/options.c
 --- a/options.c
 +++ b/options.c
index d0fed06b51772f149ef16b8594e6bdcf058eccbb..a008576fd3449c26a64130c2276ba4086ac36752 100644 (file)
@@ -35,47 +35,23 @@ diff --git a/flist.c b/flist.c
 diff --git a/generator.c b/generator.c
 --- a/generator.c
 +++ b/generator.c
-@@ -37,6 +37,8 @@ extern int implied_dirs;
+@@ -37,6 +37,7 @@ extern int implied_dirs;
  extern int keep_dirlinks;
  extern int preserve_acls;
  extern int preserve_xattrs;
 +extern int preserve_hfs_compression;
-+extern int fs_supports_hfs_compression;
  extern int preserve_links;
  extern int preserve_devices;
  extern int preserve_specials;
-@@ -1385,13 +1387,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
-                               goto cleanup;
-                       }
-               }
--#ifdef SUPPORT_XATTRS
--              if (preserve_xattrs && statret == 1)
--                      copy_xattrs(fnamecmpbuf, fname);
--#endif
--              if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
--                  && INFO_GTE(NAME, 1) && code != FNONE && f_out != -1)
--                      rprintf(code, "%s/\n", fname);
-               /* We need to ensure that the dirs in the transfer have writable
-                * permissions during the time we are putting files within them.
-@@ -1401,6 +1396,16 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1396,6 +1397,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                 && make_mutable(fname, file->mode, F_FFLAGS(file), force_change))
                        need_retouch_dir_perms = 1;
  #endif
-+
-+#ifdef SUPPORT_XATTRS
-+              /* Copy directory xattrs for a directory that already existed */
-+              if (preserve_xattrs && statret == 1)
-+                      copy_xattrs(fnamecmpbuf, fname);
-+#endif
-+              if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
-+                  && INFO_GTE(NAME, 1) && code != FNONE && f_out != -1)
-+                      rprintf(code, "%s/\n", fname);
 +
  #ifdef HAVE_CHMOD
                if (!am_root && !(file->mode & S_IWUSR) && dir_tweaking) {
                        mode_t mode = file->mode | S_IWUSR;
-@@ -1678,6 +1683,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1681,6 +1683,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                                        fname, fnamecmpbuf);
                        }
                        sx.st.st_size = F_LENGTH(fuzzy_file);
@@ -90,7 +66,7 @@ diff --git a/generator.c b/generator.c
                        statret = 0;
                        fnamecmp = fnamecmpbuf;
                        fnamecmp_type = FNAMECMP_FUZZY;
-@@ -1853,6 +1866,18 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1856,6 +1866,18 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
        if (read_batch)
                goto cleanup;
  
@@ -99,7 +75,7 @@ diff --git a/generator.c b/generator.c
 +              /* At this point the attrs have already been copied, we don't need to transfer a data fork
 +               * If my filesystem doesn't support HFS compression, the existing file's content
 +               * will not be automatically truncated, so we'll do that manually here */
-+              if (!fs_supports_hfs_compression && sx.st.st_size > 0) {
++              if (preserve_hfs_compression && sx.st.st_size > 0) {
 +                      if (ftruncate(fd, 0) == 0)
 +                              sx.st.st_size = 0;
 +              }
@@ -181,27 +157,18 @@ diff --git a/lib/sysxattrs.c b/lib/sysxattrs.c
 diff --git a/main.c b/main.c
 --- a/main.c
 +++ b/main.c
-@@ -27,6 +27,19 @@
- #include <locale.h>
+@@ -29,6 +29,10 @@
+ #ifdef SUPPORT_FORCE_CHANGE
+ #include <sys/sysctl.h>
  #endif
 +#ifdef SUPPORT_HFS_COMPRESSION
-+/* For getattrlist() */
-+#include <sys/attr.h>
-+/* For statfs(): */
-+#include <sys/mount.h>
-+/* For dirname() */
-+#include <libgen.h>
-+#endif
-+
-+#ifdef SUPPORT_FORCE_CHANGE
-+#include <sys/sysctl.h>
++#include <sys/attr.h> /* For getattrlist() */
++#include <sys/mount.h> /* For statfs() */
 +#endif
-+
  extern int dry_run;
  extern int list_only;
- extern int io_timeout;
-@@ -50,7 +63,9 @@ extern int copy_dirlinks;
+@@ -53,7 +57,9 @@ extern int copy_dirlinks;
  extern int copy_unsafe_links;
  extern int keep_dirlinks;
  extern int preserve_hard_links;
@@ -211,7 +178,7 @@ diff --git a/main.c b/main.c
  extern int file_total;
  extern int recurse;
  extern int xfer_dirs;
-@@ -102,6 +117,7 @@ int daemon_over_rsh = 0;
+@@ -105,6 +111,7 @@ int daemon_over_rsh = 0;
  mode_t orig_umask = 0;
  int batch_gen_fd = -1;
  int sender_keeps_checksum = 0;
@@ -219,128 +186,89 @@ diff --git a/main.c b/main.c
  
  /* There's probably never more than at most 2 outstanding child processes,
   * but set it higher, just in case. */
-@@ -1062,6 +1078,86 @@ int child_main(int argc, char *argv[])
-       return 0;
+@@ -557,6 +564,43 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
+       return 0; /* not reached */
  }
  
 +#ifdef SUPPORT_HFS_COMPRESSION
-+static int filesystem_supports_hfs_compression(const char *path)
++static void hfs_receiver_check(const char *dest_path)
 +{
 +      struct statfs fsb;
-+      char *parent;
-+      int statfs_ret, saved_err;
-+
-+      statfs_ret = statfs(path, &fsb);
-+      if (statfs_ret != 0) {
-+              saved_err = errno;
-+              if ((parent = (char *)dirname((char *)path)) != NULL)
-+                      statfs_ret = statfs(parent, &fsb);
-+              errno = saved_err;
++      struct attrlist attrs;
++      struct {
++              int32_t len;
++              vol_capabilities_set_t caps;
++      } attrData;
++
++      if (preserve_hfs_compression != 1)
++              return; /* Nothing to check if --hfs-compression option isn't enabled. */
++
++      if (statfs(dest_path, &fsb) < 0) {
++              rsyserr(FERROR, errno, "statfs %s failed", full_fname(dest_path));
++              exit_cleanup(RERR_FILESELECT);
 +      }
 +
-+      if (statfs_ret == 0) {
-+              struct attrlist attrs;
-+              struct {
-+                      int32_t len;
-+                      vol_capabilities_set_t caps;
-+              } attrData;
-+
-+              bzero(&attrs, sizeof(attrs));
-+              attrs.bitmapcount = ATTR_BIT_MAP_COUNT;
-+              attrs.volattr = ATTR_VOL_CAPABILITIES;
-+
-+              bzero(&attrData, sizeof(attrData));
-+              attrData.len = sizeof(attrData);
-+
-+              int ret = getattrlist(fsb.f_mntonname, &attrs, &attrData, sizeof(attrData), 0);
-+              if (ret == 0) {
-+                      if (attrData.caps[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_DECMPFS_COMPRESSION) {
-+                              /* Compression is supported */
-+                              return 1;
-+                      }
-+              } else {
-+                      rprintf(FERROR, "Failure in getattrlist while determining HFS compression support on %s (%s): %s\n", path, who_am_i(), strerror(errno));
-+              }
-+      } else {
-+              rprintf(FERROR, "Failure in statfs while determining HFS compression support on %s (%s): %s\n", path, who_am_i(), strerror(errno));
++      bzero(&attrs, sizeof attrs);
++      attrs.bitmapcount = ATTR_BIT_MAP_COUNT;
++      attrs.volattr = ATTR_VOL_CAPABILITIES;
++
++      bzero(&attrData, sizeof attrData);
++      attrData.len = sizeof attrData;
++
++      if (getattrlist(fsb.f_mntonname, &attrs, &attrData, sizeof attrData, 0) < 0) {
++              rsyserr(FERROR, errno, "getattrlist %s failed", full_fname(dest_path));
++              exit_cleanup(RERR_FILESELECT);
++      }
++
++      if (!(attrData.caps[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_DECMPFS_COMPRESSION)) {
++              rprintf(FERROR, "The destination filesystem does not support HFS+ compression.\n");
++              exit_cleanup(RERR_UNSUPPORTED);
 +      }
-+      return 0;
 +}
 +#endif
 +
-+#if defined SUPPORT_HFS_COMPRESSION || defined SUPPORT_FORCE_CHANGE
-+static void do_filesystem_compatibility_checks(const char *path)
-+{
+ /* The receiving side operates in one of two modes:
+  *
+  * 1. it receives any number of files into a destination directory,
+@@ -615,6 +659,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
+                               exit_cleanup(RERR_FILESELECT);
+                       }
+                       filesystem_dev = st.st_dev; /* ensures --force works right w/-x */
 +#ifdef SUPPORT_HFS_COMPRESSION
-+      fs_supports_hfs_compression = filesystem_supports_hfs_compression(path);
-+      if (preserve_hfs_compression > 0) {
-+              /* If the filesystem doesn't support compression and decmpfs
-+               * protection wasn't requested, disable support for compression */
-+              if (!fs_supports_hfs_compression && preserve_hfs_compression < 2) {
-+                      preserve_hfs_compression = 0;
-+                      rprintf(FINFO, "%s: Disabling HFS compression support, %s doesn't support it (use --protect-decmpfs to force protection of the com.apple.decmpfs extended attribute).\n", who_am_i(), path);
-+              }
-+      }
++                      hfs_receiver_check(dest_path);
 +#endif
-+
-+#ifdef SUPPORT_FORCE_CHANGE
-+      if (force_change & SYS_IMMUTABLE) {
-+              /* determine whether we'll be able to unlock a system immutable item */
-+              int mib[2];
-+              int securityLevel = 0;
-+              size_t len = sizeof(securityLevel);
-+
-+              mib[0] = CTL_KERN;
-+              mib[1] = KERN_SECURELVL;
-+              if (sysctl(mib, 2, &securityLevel, &len, NULL, 0) == 0 && securityLevel > 0) {
-+                      rprintf(FERROR, "System security level is too high to force mutability on system immutable files and directories.\n");
-+                      /*force_change ~= ~SYS_IMMUTABLE;*/
-+                      exit_cleanup(RERR_UNSUPPORTED);
-+              }
-+      }
+                       return NULL;
+               }
+               if (file_total > 1) {
+@@ -675,7 +722,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
+                               full_fname(dest_path));
+                       exit_cleanup(RERR_FILESELECT);
+               }
+-
++#ifdef SUPPORT_HFS_COMPRESSION
++              hfs_receiver_check(dest_path);
 +#endif
-+
-+      /* TODO: ACLs and xattrs? */
-+}
+               return NULL;
+       }
+@@ -695,6 +744,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
+                       full_fname(dest_path));
+               exit_cleanup(RERR_FILESELECT);
+       }
++#ifdef SUPPORT_HFS_COMPRESSION
++      hfs_receiver_check(dest_path);
 +#endif
+       *cp = '/';
+       return cp + 1;
+@@ -1081,7 +1133,6 @@ int child_main(int argc, char *argv[])
+       return 0;
+ }
  
+-
  void start_server(int f_in, int f_out, int argc, char *argv[])
  {
-@@ -1069,6 +1165,10 @@ void start_server(int f_in, int f_out, int argc, char *argv[])
-       set_nonblocking(f_out);
-       io_set_sock_fds(f_in, f_out);
-+#if defined SUPPORT_HFS_COMPRESSION || defined SUPPORT_FORCE_CHANGE
-+      if (!local_server)
-+              do_filesystem_compatibility_checks(argv[argc - 1]);
-+#endif
-       setup_protocol(f_out, f_in);
-       if (protocol_version >= 23)
-@@ -1269,7 +1369,13 @@ static int start_client(int argc, char *argv[])
-                       am_sender = 0;
-                       if (rsync_port)
-                               daemon_over_rsh = shell_cmd ? 1 : -1;
-+#if defined SUPPORT_HFS_COMPRESSION || defined SUPPORT_FORCE_CHANGE
-+                      do_filesystem_compatibility_checks(*argv);
-+#endif
-               } else { /* source is local, check dest arg */
-+#if defined SUPPORT_HFS_COMPRESSION || defined SUPPORT_FORCE_CHANGE
-+                      do_filesystem_compatibility_checks(argv[0]);
-+#endif
-                       am_sender = 1;
-                       if (argc > 1) {
-@@ -1297,6 +1403,9 @@ static int start_client(int argc, char *argv[])
-                                       exit_cleanup(RERR_SYNTAX);
-                               }
-                               shell_machine = NULL;
-+#if defined SUPPORT_HFS_COMPRESSION || defined SUPPORT_FORCE_CHANGE
-+                              do_filesystem_compatibility_checks(p);
-+#endif
-                       } else { /* hostspec was found, so dest is remote */
-                               argv[argc] = path;
-                               if (rsync_port)
+       set_nonblocking(f_in);
 diff --git a/options.c b/options.c
 --- a/options.c
 +++ b/options.c
@@ -357,8 +285,8 @@ diff --git a/options.c b/options.c
    rprintf(F," -X, --xattrs                preserve extended attributes\n");
  #endif
 +#ifdef SUPPORT_HFS_COMPRESSION
-+  rprintf(F,"     --hfs-compression       preserve HFS compression (if source & destination support it)\n");
-+  rprintf(F,"     --protect-decmpfs       preserve HFS compression (regardless of volume support)\n");
++  rprintf(F,"     --hfs-compression       preserve HFS compression if supported\n");
++  rprintf(F,"     --protect-decmpfs       preserve HFS compression as xattrs\n");
 +#endif
    rprintf(F," -o, --owner                 preserve owner (super-user only)\n");
    rprintf(F," -g, --group                 preserve group\n");
@@ -369,35 +297,30 @@ diff --git a/options.c b/options.c
  #endif
 +#ifdef SUPPORT_HFS_COMPRESSION
 +  {"hfs-compression",  0,  POPT_ARG_VAL,    &preserve_hfs_compression, 1, 0, 0 },
-+  {"protect-decmpfs",  0,  POPT_ARG_VAL,    &preserve_hfs_compression, 2, 0, 0 },
 +  {"no-hfs-compression",0, POPT_ARG_VAL,    &preserve_hfs_compression, 0, 0, 0 },
++  {"protect-decmpfs",  0,  POPT_ARG_VAL,    &preserve_hfs_compression, 2, 0, 0 },
 +  {"no-protect-decmpfs",0, POPT_ARG_VAL,    &preserve_hfs_compression, 0, 0, 0 },
 +#endif
    {"ignore-errors",    0,  POPT_ARG_VAL,    &ignore_errors, 1, 0, 0 },
    {"no-ignore-errors", 0,  POPT_ARG_VAL,    &ignore_errors, 0, 0, 0 },
    {"max-delete",       0,  POPT_ARG_INT,    &max_delete, 0, 0, 0 },
-@@ -1902,6 +1913,20 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -1902,6 +1913,15 @@ int parse_arguments(int *argc_p, const char ***argv_p)
        }
  #endif
  
-+      if (preserve_hfs_compression) {
 +#ifdef SUPPORT_HFS_COMPRESSION
++      if (preserve_hfs_compression) {
 +              if (!preserve_xattrs)
 +                      preserve_xattrs = 1;
 +              if (!preserve_fileflags)
 +                      preserve_fileflags = 1;
-+#else
-+              snprintf(err_buf,sizeof(err_buf),
-+                       "HFS compression is not supported on this %s\n",
-+                       am_server ? "server" : "client");
-+              return 0;
-+#endif
 +      }
++#endif
 +
        if (write_batch && read_batch) {
                snprintf(err_buf, sizeof err_buf,
                        "--write-batch and --read-batch can not be used together\n");
-@@ -2486,6 +2511,11 @@ void server_options(char **args, int *argc_p)
+@@ -2486,6 +2506,11 @@ void server_options(char **args, int *argc_p)
        if (preserve_fileflags)
                args[ac++] = "--fileflags";
  
@@ -483,35 +406,29 @@ diff --git a/rsync.yo b/rsync.yo
       --chmod=CHMOD           affect file and/or directory permissions
   -A, --acls                  preserve ACLs (implies -p)
   -X, --xattrs                preserve extended attributes
-+     --hfs-compression       preserve HFS compression (if source & destination support it)
-+     --protect-decmpfs       preserve HFS compression (regardless of volume support)
++     --hfs-compression       preserve HFS compression if supported
++     --protect-decmpfs       preserve HFS compression as xattrs
   -o, --owner                 preserve owner (super-user only)
   -g, --group                 preserve group
       --devices               preserve device files (super-user only)
-@@ -1087,6 +1089,48 @@ flags on files and directories that are being updated or deleted on the
+@@ -1087,6 +1089,42 @@ flags on files and directories that are being updated or deleted on the
  receiving side.  It does not try to affect user flags.  This option overrides
  bf(--force-change) and bf(--force-schange).
  
 +dit(bf(--hfs-compression)) This option causes rsync to preserve HFS+
-+compression on filesystems that support it. Filesystem compression was
-+introduced to HFS+ in Mac OS 10.6. A file that is compressed has no data in
-+its data fork. Rather, the compressed data is stored in an extended attribute
-+named com.apple.decmpfs and a file flag is set to indicate that the file is
-+compressed (UF_COMPRESSED). HFS+ decompresses this data "on-the-fly" and
-+presents it to the operating system as a normal file. Normal attempts to copy
-+compressed files (e.g. in the Finder, via cp, ditto, etc.) will copy the
-+file's decompressed contents, remove the UF_COMPRESSED file flag, and discard
-+the com.apple.decmpfs extended attribute. This option will preserve the data
-+in the com.apple.decmpfs extended attribute and ignore the synthesized data
-+fork contents as long as both the source and destination filesystems support
-+HFS+ compression.
-+
-+If the source or destination filesystem does not support HFS+ compression,
-+this option will be disabled for both ends of the transfer. Compressed files
-+will be decompressed on the destination, data in the com.apple.decmpfs
-+extended attribute will be discarded, and the UF_COMPRESSED flag will not be
-+set. This option is appropriate if viewing the contents of compressed files is
-+required on operating systems that do not support HFS+ compression.
++compression if the destination filesystem supports it.  If the destination
++does not support it, rsync will exit with an error.
++
++Filesystem compression was introduced to HFS+ in Mac OS 10.6. A file that is
++compressed has no data in its data fork. Rather, the compressed data is stored
++in an extended attribute named com.apple.decmpfs and a file flag is set to
++indicate that the file is compressed (UF_COMPRESSED). HFS+ decompresses this
++data "on-the-fly" and presents it to the operating system as a normal file.
++Normal attempts to copy compressed files (e.g. in the Finder, via cp, ditto,
++etc.) will copy the file's decompressed contents, remove the UF_COMPRESSED file
++flag, and discard the com.apple.decmpfs extended attribute. This option will
++preserve the data in the com.apple.decmpfs extended attribute and ignore the
++synthesized data in the file contents.
 +
 +This option implies both bf(--fileflags) and (--xattrs).
 +
@@ -523,14 +440,14 @@ diff --git a/rsync.yo b/rsync.yo
 +or restoring the Mac OS X filesystem.
 +
 +This option will transfer the com.apple.decmpfs extended attribute regardless
-+of support on the source or destination. If a source file is compressed and an
-+existing file on the destination is not compressed, the data fork of the
-+destination file will be truncated and the com.apple.decmpfs xattr will be
-+transferred instead. Note that compressed files will not be readable to the
-+operating system of the destination if that operating system does not support
-+HFS+ compression. Once restored (with or without this option) to an operating
-+system that supports HFS+ compression, however, these files will be accessible
-+as usual.
++of support on the destination. If a source file is compressed and an existing
++file on the destination is not compressed, the data fork of the destination
++file will be truncated and the com.apple.decmpfs xattr will be transferred
++instead. Note that compressed files will not be readable to the operating
++system of the destination if that operating system does not support HFS+
++compression. Once restored (with or without this option) to an operating system
++that supports HFS+ compression, however, these files will be accessible as
++usual.
 +
 +This option implies bf(--fileflags) and bf(--xattrs).
 +