+/* Each time rsync changes to a new directory it call this function to
+ * handle all the per-dir merge-files. The "dir" value is the current path
+ * relative to curr_dir (which might not be null-terminated). We copy it
+ * into dirbuf so that we can easily append a file name on the end. */
+void *push_local_excludes(const char *dir, unsigned int dirlen)
+{
+ struct exclude_list_struct *ap, *push;
+ int i;
+
+ set_excludes_dir(dir, dirlen);
+
+ if (!mergelist_cnt)
+ return NULL;
+
+ push = new_array(struct exclude_list_struct, mergelist_cnt);
+ if (!push)
+ out_of_memory("push_local_excludes");
+
+ for (i = 0, ap = push; i < mergelist_cnt; i++) {
+ memcpy(ap++, mergelist_parents[i]->u.mergelist,
+ sizeof (struct exclude_list_struct));
+ }
+
+ /* Note: add_exclude_file() might increase mergelist_cnt, so keep
+ * this loop separate from the above loop. */
+ for (i = 0; i < mergelist_cnt; i++) {
+ struct exclude_struct *ex = mergelist_parents[i];
+ struct exclude_list_struct *lp = ex->u.mergelist;
+ int flags = 0;
+
+ if (verbose > 2) {
+ rprintf(FINFO, "[%s] pushing exclude list%s\n",
+ who_am_i(), lp->debug_type);
+ }
+
+ lp->tail = NULL; /* Switch any local rules to inherited. */
+ if (ex->match_flags & MATCHFLG_NO_INHERIT)
+ lp->head = NULL;
+ if (ex->match_flags & MATCHFLG_WORD_SPLIT)
+ flags |= XFLG_WORD_SPLIT;
+ if (ex->match_flags & MATCHFLG_NO_PREFIXES)
+ flags |= XFLG_NO_PREFIXES;
+ if (ex->match_flags & MATCHFLG_INCLUDE)
+ flags |= XFLG_DEF_INCLUDE;
+ else if (ex->match_flags & MATCHFLG_NO_PREFIXES)
+ flags |= XFLG_DEF_EXCLUDE;
+
+ if (ex->match_flags & MATCHFLG_FINISH_SETUP) {
+ ex->match_flags &= ~MATCHFLG_FINISH_SETUP;
+ if (setup_merge_file(ex, lp, flags))
+ set_excludes_dir(dir, dirlen);
+ }
+
+ if (strlcpy(dirbuf + dirbuf_len, ex->pattern,
+ MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len)
+ add_exclude_file(lp, dirbuf, flags | XFLG_ABS_PATH);
+ else {
+ io_error |= IOERR_GENERAL;
+ rprintf(FINFO,
+ "cannot add local excludes in long-named directory %s\n",
+ full_fname(dirbuf));
+ }
+ dirbuf[dirbuf_len] = '\0';
+ }
+
+ return (void*)push;
+}
+
+void pop_local_excludes(void *mem)
+{
+ struct exclude_list_struct *ap, *pop = (struct exclude_list_struct*)mem;
+ int i;
+
+ for (i = mergelist_cnt; i-- > 0; ) {
+ struct exclude_struct *ex = mergelist_parents[i];
+ struct exclude_list_struct *lp = ex->u.mergelist;
+
+ if (verbose > 2) {
+ rprintf(FINFO, "[%s] popping exclude list%s\n",
+ who_am_i(), lp->debug_type);
+ }
+
+ clear_exclude_list(lp);
+ }
+
+ if (!pop)
+ return;
+
+ for (i = 0, ap = pop; i < mergelist_cnt; i++) {
+ memcpy(mergelist_parents[i]->u.mergelist, ap++,
+ sizeof (struct exclude_list_struct));
+ }
+
+ free(pop);