--- generator.c.orig 2006-01-09 13:04:42.000000000 -0600 +++ generator.c 2006-01-09 13:09:18.000000000 -0600 @@ -23,6 +23,10 @@ #include "rsync.h" +#ifdef HAVE_COPYFILE +#include +#endif + extern int verbose; extern int dry_run; extern int do_xfers; @@ -89,6 +93,10 @@ extern struct file_list *the_file_list; extern struct filter_list_struct server_filter_list; +#ifdef EA_SUPPORT +extern int extended_attributes; +#endif + static int deletion_count = 0; /* used to implement --max-delete */ @@ -125,6 +133,18 @@ deletion_count--; return 0; } +#ifdef EA_SUPPORT + /* Prevent flooding the syslog when trying to delete the + synthetic (= fake) file containing extended attributes. */ +#ifdef HAVE_COPYFILE + if (errno == ENOENT && extended_attributes + && !strncmp(basename(fname), "._", 2)) { + if (verbose) + rprintf(FINFO, "synthetic file %s could not be deleted\n", + safe_fname(fname)); + } else +#endif +#endif rsyserr(FERROR, errno, "delete_file: unlink %s failed", full_fname(fname)); return -1; @@ -1152,6 +1172,10 @@ int save_opt_ignore_existing = opt_ignore_existing; int save_do_progress = do_progress; int save_make_backups = make_backups; +#ifdef HAVE_COPYFILE + int ea_map[flist->count]; + int ea_saved = -1; +#endif if (protocol_version >= 29) { itemizing = 1; @@ -1195,9 +1219,77 @@ * notice that and let us know via the redo pipe (or its closing). */ ignore_timeout = 1; +#ifdef HAVE_COPYFILE + /* APPLE: extended attribute files (._foo) need to be transferred + * after the corresponding file (foo). This creates a map the size + * of flist with the number of the file that preempts the current + * file's delivery. Set to -1 if there's nothing to do. + */ + if (extended_attributes) { + int j; + struct file_struct *file2; + struct file_struct *file3; + + if (verbose > 3) + rprintf(FINFO,"initializing extended attribute map\n"); + + for (i = 0; i < flist->count; ++i) { + ea_map[i] = -1; + file2 = flist->files[i]; + + if (!file2->basename || strncmp(file2->basename, "._", 2)) + continue; + + for (j = i; j < flist->count; ++j) { + file3 = flist->files[j]; + + if (!file3->basename) + continue; + + if(!(file2->dirname || file3->dirname) + || (file2->dirname && file3->dirname && + !strcmp(file3->dirname, file2->dirname))) { + + if(!strcmp(file3->basename, file2->basename + 2)) { + ea_map[i] = j; + + if (verbose > 4) + rprintf(FINFO,"mapped %s/%s (%d) -> %s/%s (%d)\n", + (file2->dirname) ? file2->dirname : ".", + file2->basename, i, + (file2->dirname) ? file2->dirname : ".", + file3->basename, j); + break; + } + } + } + } + } +#endif + for (i = 0; i < flist->count; i++) { struct file_struct *file = flist->files[i]; +#ifdef HAVE_COPYFILE + if (extended_attributes) { + if(ea_map[i] < -1) + continue; + + if(ea_map[i] > 0) { + /* save the current index and set it to the + * file to skip to + */ + if (verbose > 4) + rprintf(FINFO,"skipping from %d to %d\n", i, ea_map[i]); + + ea_saved = i; + i = ea_map[i]; + ea_map[i] = -1; + } +next: file = flist->files[i]; + } +#endif + if (!file->basename) continue; @@ -1227,6 +1319,17 @@ maybe_send_keepalive(); else if (!(i % 200)) maybe_flush_socket(); + +#ifdef HAVE_COPYFILE + if (extended_attributes) { + if(ea_saved > -1) { + ea_map[i] = -2; + i = ea_saved; + ea_saved = -1; + goto next; + } + } +#endif } recv_generator(NULL, NULL, 0, 0, 0, code, -1); if (delete_during)