From cbdf862c63c8b1b764247668a83430da0bf49559 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sun, 30 Mar 2008 23:48:35 -0700 Subject: [PATCH] The patches for 3.0.1pre3. --- atimes.diff | 12 +- checksum-reading.diff | 30 +- checksum-updating.diff | 50 +- checksum-xattr.diff | 2 +- copy-devices.diff | 2 +- crtimes.diff | 16 +- cvs-entries.diff | 2 +- db.diff | 1215 ++++++++++++++++++++++++++++++++ detect-renamed-lax.diff | 2 +- detect-renamed.diff | 18 +- downdate.diff | 6 +- fileflags.diff | 20 +- ignore-case.diff | 4 +- link-by-hash.diff | 2 +- openssl-support.diff | 2 +- preallocate.diff | 2 +- remote-option.diff | 77 +- slow-down.diff | 2 +- slp.diff | 2 +- source-filter_dest-filter.diff | 2 +- stdout.diff | 2 +- usermap.diff | 2 +- 22 files changed, 1331 insertions(+), 141 deletions(-) create mode 100644 db.diff diff --git a/atimes.diff b/atimes.diff index b25b217..462a40b 100644 --- a/atimes.diff +++ b/atimes.diff @@ -44,7 +44,7 @@ diff --git a/flist.c b/flist.c extern int relative_paths; extern int implied_dirs; extern int file_extra_cnt; -@@ -379,7 +380,7 @@ int push_pathname(const char *dir, int len) +@@ -384,7 +385,7 @@ int change_pathname(struct file_struct *file, const char *dir, int dirlen) static void send_file_entry(int f, const char *fname, struct file_struct *file, int ndx, int first_ndx) { @@ -53,7 +53,7 @@ diff --git a/flist.c b/flist.c static mode_t mode; #ifdef SUPPORT_HARD_LINKS static int64 dev; -@@ -457,6 +458,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, +@@ -458,6 +459,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, xflags |= XMIT_SAME_TIME; else modtime = file->modtime; @@ -111,7 +111,7 @@ diff --git a/flist.c b/flist.c if (unsort_ndx) F_NDX(file) = flist->used + flist->ndx_start; -@@ -1215,6 +1237,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, +@@ -1226,6 +1248,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, F_OWNER(file) = st.st_uid; if (gid_ndx) /* Check gid_ndx instead of preserve_gid for del support */ F_GROUP(file) = st.st_gid; @@ -177,7 +177,7 @@ diff --git a/generator.c b/generator.c f_name(f, NULL)); } } -@@ -2017,7 +2026,7 @@ static void touch_up_dirs(struct file_list *flist, int ndx) +@@ -2016,7 +2025,7 @@ static void touch_up_dirs(struct file_list *flist, int ndx) STRUCT_STAT st; if (link_stat(fname, &st, 0) == 0 && cmp_time(st.st_mtime, file->modtime) != 0) @@ -352,7 +352,7 @@ diff --git a/rsync.h b/rsync.h /* These flags are used in the live flist data. */ -@@ -151,6 +152,7 @@ +@@ -152,6 +153,7 @@ #define ATTRS_REPORT (1<<0) #define ATTRS_SKIP_MTIME (1<<1) @@ -360,7 +360,7 @@ diff --git a/rsync.h b/rsync.h #define FULL_FLUSH 1 #define NORMAL_FLUSH 0 -@@ -622,12 +624,14 @@ extern int file_extra_cnt; +@@ -626,12 +628,14 @@ extern int file_extra_cnt; extern int inc_recurse; extern int uid_ndx; extern int gid_ndx; diff --git a/checksum-reading.diff b/checksum-reading.diff index 784a91b..159c7ad 100644 --- a/checksum-reading.diff +++ b/checksum-reading.diff @@ -103,7 +103,7 @@ diff --git a/flist.c b/flist.c static void output_flist(struct file_list *flist); void init_flist(void) -@@ -350,6 +363,238 @@ static void flist_done_allocating(struct file_list *flist) +@@ -338,6 +351,238 @@ static void flist_done_allocating(struct file_list *flist) flist->pool_boundary = ptr; } @@ -339,9 +339,9 @@ diff --git a/flist.c b/flist.c + file_checksum(fname, stp->st_size, sum_buf); +} + - int push_pathname(const char *dir, int len) - { - if (dir == pathname) + /* Call this with EITHER (1) "file, NULL, 0" to chdir() to the file's + * F_PATHNAME(), or (2) "NULL, dir, dirlen" to chdir() to the supplied dir, + * with dir == NULL taken to be the starting directory, and dirlen < 0 @@ -1010,7 +1255,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, STRUCT_STAT *stp, int flags, int filter_level) { @@ -351,7 +351,7 @@ diff --git a/flist.c b/flist.c struct file_struct *file; char thisname[MAXPATHLEN]; char linkname[MAXPATHLEN]; -@@ -1149,9 +1394,16 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, +@@ -1160,9 +1405,16 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, memcpy(lastdir, thisname, len); lastdir[len] = '\0'; lastdir_len = len; @@ -369,7 +369,7 @@ diff --git a/flist.c b/flist.c basename_len = strlen(basename) + 1; /* count the '\0' */ #ifdef SUPPORT_LINKS -@@ -1224,14 +1476,18 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, +@@ -1235,14 +1487,18 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, memcpy(bp + basename_len, linkname, linkname_len); #endif @@ -391,7 +391,7 @@ diff --git a/flist.c b/flist.c /* This code is only used by the receiver when it is building * a list of files for a delete pass. */ if (keep_dirlinks && linkname_len && flist) { -@@ -2147,7 +2403,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) +@@ -2155,7 +2411,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) * file-list to check if this is a 1-file xfer. */ send_extra_file_list(f, 1); } @@ -401,7 +401,7 @@ diff --git a/flist.c b/flist.c return flist; } -@@ -2249,7 +2506,7 @@ struct file_list *recv_file_list(int f) +@@ -2257,7 +2514,7 @@ struct file_list *recv_file_list(int f) else if (f >= 0) recv_id_list(f, flist); @@ -410,7 +410,7 @@ diff --git a/flist.c b/flist.c if (protocol_version < 30) { /* Recv the io_error flag */ -@@ -2447,7 +2704,7 @@ void flist_free(struct file_list *flist) +@@ -2455,7 +2712,7 @@ void flist_free(struct file_list *flist) /* This routine ensures we don't have any duplicate names in our file list. * duplicate names can cause corruption because of the pipelining. */ @@ -419,7 +419,7 @@ diff --git a/flist.c b/flist.c { char fbuf[MAXPATHLEN]; int i, prev_i; -@@ -2498,7 +2755,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root) +@@ -2506,7 +2763,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root) /* If one is a dir and the other is not, we want to * keep the dir because it might have contents in the * list. Otherwise keep the first one. */ @@ -428,7 +428,7 @@ diff --git a/flist.c b/flist.c struct file_struct *fp = flist->sorted[j]; if (!S_ISDIR(fp->mode)) keep = i, drop = j; -@@ -2514,8 +2771,8 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root) +@@ -2522,8 +2779,8 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root) } else keep = j, drop = i; @@ -439,7 +439,7 @@ diff --git a/flist.c b/flist.c rprintf(FINFO, "removing duplicate name %s from file list (%d)\n", f_name(file, fbuf), drop + flist->ndx_start); -@@ -2537,7 +2794,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root) +@@ -2545,7 +2802,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root) } flist->high = prev_i; @@ -529,7 +529,7 @@ diff --git a/generator.c b/generator.c } statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir); -@@ -1776,7 +1785,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1775,7 +1784,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, ; else if (fnamecmp_type == FNAMECMP_FUZZY) ; @@ -687,7 +687,7 @@ diff --git a/options.c b/options.c diff --git a/rsync.h b/rsync.h --- a/rsync.h +++ b/rsync.h -@@ -682,6 +682,10 @@ extern int xattrs_ndx; +@@ -686,6 +686,10 @@ extern int xattrs_ndx; #define F_SUM(f) ((char*)OPT_EXTRA(f, LEN64_BUMP(f) + HLINK_BUMP(f) \ + SUM_EXTRA_CNT - 1)) @@ -698,7 +698,7 @@ diff --git a/rsync.h b/rsync.h /* Some utility defines: */ #define F_IS_ACTIVE(f) (f)->basename[0] #define F_IS_HLINKED(f) ((f)->flags & FLAG_HLINKED) -@@ -860,6 +864,13 @@ typedef struct { +@@ -864,6 +868,13 @@ typedef struct { char fname[1]; /* has variable size */ } relnamecache; diff --git a/checksum-updating.diff b/checksum-updating.diff index e4632c1..20e9bcd 100644 --- a/checksum-updating.diff +++ b/checksum-updating.diff @@ -52,7 +52,7 @@ diff --git a/flist.c b/flist.c } *csum_cache = NULL; static void flist_sort_and_clean(struct file_list *flist, int flags); -@@ -363,7 +372,79 @@ static void flist_done_allocating(struct file_list *flist) +@@ -351,7 +360,79 @@ static void flist_done_allocating(struct file_list *flist) flist->pool_boundary = ptr; } @@ -133,7 +133,7 @@ diff --git a/flist.c b/flist.c { int slot, slots = am_sender ? 1 : basis_dir_cnt + 1; -@@ -377,6 +458,9 @@ void reset_checksum_cache() +@@ -365,6 +446,9 @@ void reset_checksum_cache() struct file_list *flist = csum_cache[slot].flist; if (flist) { @@ -143,7 +143,7 @@ diff --git a/flist.c b/flist.c /* Reset the pool memory and empty the file-list array. */ pool_free_old(flist->file_pool, pool_boundary(flist->file_pool, 0)); -@@ -387,6 +471,10 @@ void reset_checksum_cache() +@@ -375,6 +459,10 @@ void reset_checksum_cache() flist->low = 0; flist->high = -1; flist->next = NULL; @@ -154,7 +154,7 @@ diff --git a/flist.c b/flist.c } } -@@ -394,7 +482,7 @@ void reset_checksum_cache() +@@ -382,7 +470,7 @@ void reset_checksum_cache() static int add_checksum(struct file_list *flist, const char *dirname, const char *basename, int basename_len, OFF_T file_length, time_t mtime, uint32 ctime, uint32 inode, @@ -163,7 +163,7 @@ diff --git a/flist.c b/flist.c { struct file_struct *file; int alloc_len, extra_len; -@@ -411,7 +499,7 @@ static int add_checksum(struct file_list *flist, const char *dirname, +@@ -399,7 +487,7 @@ static int add_checksum(struct file_list *flist, const char *dirname, if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN)) extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN; #endif @@ -172,7 +172,7 @@ diff --git a/flist.c b/flist.c bp = pool_alloc(flist->file_pool, alloc_len, "add_checksum"); memset(bp, 0, extra_len + FILE_STRUCT_LEN); -@@ -420,7 +508,14 @@ static int add_checksum(struct file_list *flist, const char *dirname, +@@ -408,7 +496,14 @@ static int add_checksum(struct file_list *flist, const char *dirname, bp += FILE_STRUCT_LEN; memcpy(bp, basename, basename_len); @@ -187,7 +187,7 @@ diff --git a/flist.c b/flist.c file->mode = S_IFREG; file->modtime = mtime; file->len32 = (uint32)file_length; -@@ -449,10 +544,11 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam +@@ -437,10 +532,11 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam char line[MAXPATHLEN+1024], fbuf[MAXPATHLEN], sum[MAX_DIGEST_LEN]; FILE *fp; char *cp; @@ -200,7 +200,7 @@ diff --git a/flist.c b/flist.c int dlen = dirname ? strlcpy(fbuf, dirname, sizeof fbuf) : 0; if (dlen >= (int)(sizeof fbuf - 1 - RSYNCSUMS_LEN)) -@@ -473,7 +569,7 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam +@@ -461,7 +557,7 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam while (fgets(line, sizeof line, fp)) { cp = line; if (protocol_version >= 30) { @@ -209,7 +209,7 @@ diff --git a/flist.c b/flist.c if (*cp == '=') while (*++cp == '=') {} else -@@ -484,7 +580,14 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam +@@ -472,7 +568,14 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam } if (*cp == '=') { @@ -225,7 +225,7 @@ diff --git a/flist.c b/flist.c } else { for (i = 0; i < checksum_len*2; i++, cp++) { int x; -@@ -502,13 +605,14 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam +@@ -490,13 +593,14 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam else sum[i/2] = x << 4; } @@ -241,7 +241,7 @@ diff --git a/flist.c b/flist.c if (*cp == '=') while (*++cp == '=') {} else -@@ -558,24 +662,112 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam +@@ -546,24 +650,112 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam continue; strlcpy(fbuf+dlen, cp, sizeof fbuf - dlen); @@ -356,7 +356,7 @@ diff --git a/flist.c b/flist.c read_checksums(slot, flist, file->dirname); } -@@ -587,12 +779,31 @@ void get_cached_checksum(int slot, const char *fname, struct file_struct *file, +@@ -575,12 +767,31 @@ void get_cached_checksum(int slot, const char *fname, struct file_struct *file, && (checksum_files & CSF_LAX || (F_CTIME(fp) == (uint32)stp->st_ctime && F_INODE(fp) == (uint32)stp->st_ino))) { @@ -388,9 +388,9 @@ diff --git a/flist.c b/flist.c + } } - int push_pathname(const char *dir, int len) -@@ -1349,6 +1560,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, - if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) { + /* Call this with EITHER (1) "file, NULL, 0" to chdir() to the file's +@@ -1360,6 +1571,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, + if (excl_ret) { if (ignore_perishable) non_perishable_cnt++; + if (S_ISREG(st.st_mode)) @@ -398,7 +398,7 @@ diff --git a/flist.c b/flist.c return NULL; } -@@ -1395,13 +1608,13 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, +@@ -1406,13 +1619,13 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, lastdir[len] = '\0'; lastdir_len = len; if (checksum_files && am_sender && flist) @@ -414,7 +414,7 @@ diff --git a/flist.c b/flist.c } } basename_len = strlen(basename) + 1; /* count the '\0' */ -@@ -1483,7 +1696,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, +@@ -1494,7 +1707,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, if (always_checksum && am_sender && S_ISREG(st.st_mode)) { if (flist && checksum_files) @@ -423,7 +423,7 @@ diff --git a/flist.c b/flist.c else file_checksum(thisname, st.st_size, tmp_sum); } -@@ -1809,6 +2022,9 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, +@@ -1820,6 +2033,9 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, closedir(d); @@ -433,7 +433,7 @@ diff --git a/flist.c b/flist.c if (f >= 0 && recurse && !divert_dirs) { int i, end = flist->used - 1; /* send_if_directory() bumps flist->used, so use "end". */ -@@ -2405,6 +2621,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) +@@ -2413,6 +2629,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) } } else flist_eof = 1; @@ -473,15 +473,15 @@ diff --git a/generator.c b/generator.c } need_new_dirscan = 0; } -@@ -1499,6 +1501,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1498,6 +1500,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, + else change_local_filter_dir(fname, strlen(fname), F_DEPTH(file)); - } + upcoming_whole_dir = file->flags & FLAG_CONTENT_DIR && f_out != -1 ? 1 : 0; goto cleanup; } -@@ -1791,6 +1794,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1790,6 +1793,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, handle_partial_dir(partialptr, PDIR_DELETE); } set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); @@ -490,7 +490,7 @@ diff --git a/generator.c b/generator.c if (itemizing) itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL); #ifdef SUPPORT_HARD_LINKS -@@ -2205,6 +2210,7 @@ void generate_files(int f_out, const char *local_name) +@@ -2204,6 +2209,7 @@ void generate_files(int f_out, const char *local_name) } else change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp)); } @@ -498,7 +498,7 @@ diff --git a/generator.c b/generator.c } for (i = cur_flist->low; i <= cur_flist->high; i++) { struct file_struct *file = cur_flist->sorted[i]; -@@ -2285,6 +2291,9 @@ void generate_files(int f_out, const char *local_name) +@@ -2284,6 +2290,9 @@ void generate_files(int f_out, const char *local_name) wait_for_receiver(); } @@ -595,7 +595,7 @@ diff --git a/receiver.c b/receiver.c diff --git a/rsync.h b/rsync.h --- a/rsync.h +++ b/rsync.h -@@ -866,6 +866,8 @@ typedef struct { +@@ -870,6 +870,8 @@ typedef struct { #define CSF_ENABLE (1<<1) #define CSF_LAX (1<<2) diff --git a/checksum-xattr.diff b/checksum-xattr.diff index f2d76a6..88c2e94 100644 --- a/checksum-xattr.diff +++ b/checksum-xattr.diff @@ -11,7 +11,7 @@ To use this patch, run these commands for a successful build: diff --git a/flist.c b/flist.c --- a/flist.c +++ b/flist.c -@@ -1224,7 +1224,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, +@@ -1235,7 +1235,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, memcpy(bp + basename_len, linkname, linkname_len); #endif diff --git a/copy-devices.diff b/copy-devices.diff index 3ebc62d..60aca11 100644 --- a/copy-devices.diff +++ b/copy-devices.diff @@ -19,7 +19,7 @@ diff --git a/generator.c b/generator.c extern int preserve_specials; extern int preserve_hard_links; extern int preserve_executability; -@@ -1671,7 +1672,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1670,7 +1671,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, goto cleanup; } diff --git a/crtimes.diff b/crtimes.diff index c92b428..1d50bc9 100644 --- a/crtimes.diff +++ b/crtimes.diff @@ -48,7 +48,7 @@ diff --git a/flist.c b/flist.c extern int relative_paths; extern int implied_dirs; extern int file_extra_cnt; -@@ -380,7 +381,7 @@ int push_pathname(const char *dir, int len) +@@ -385,7 +386,7 @@ int change_pathname(struct file_struct *file, const char *dir, int dirlen) static void send_file_entry(int f, const char *fname, struct file_struct *file, int ndx, int first_ndx) { @@ -57,7 +57,7 @@ diff --git a/flist.c b/flist.c static mode_t mode; #ifdef SUPPORT_FILEFLAGS static uint32 fileflags; -@@ -469,6 +470,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, +@@ -470,6 +471,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, xflags |= XMIT_SAME_TIME; else modtime = file->modtime; @@ -118,7 +118,7 @@ diff --git a/flist.c b/flist.c if (unsort_ndx) F_NDX(file) = flist->used + flist->ndx_start; -@@ -1246,6 +1271,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, +@@ -1257,6 +1282,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, F_OWNER(file) = st.st_uid; if (gid_ndx) /* Check gid_ndx instead of preserve_gid for del support */ F_GROUP(file) = st.st_gid; @@ -338,7 +338,7 @@ diff --git a/rsync.h b/rsync.h #define XMIT_SAME_FLAGS (1<<14) /* protocols ?? - now */ /* These flags are used in the live flist data. */ -@@ -153,6 +154,7 @@ +@@ -154,6 +155,7 @@ #define ATTRS_REPORT (1<<0) #define ATTRS_SKIP_MTIME (1<<1) #define ATTRS_DELAY_IMMUTABLE (1<<2) @@ -346,7 +346,7 @@ diff --git a/rsync.h b/rsync.h #define FULL_FLUSH 1 #define NORMAL_FLUSH 0 -@@ -169,7 +171,7 @@ +@@ -170,7 +172,7 @@ #define FNAMECMP_FUZZY 0x83 /* For use by the itemize_changes code */ @@ -355,7 +355,7 @@ diff --git a/rsync.h b/rsync.h #define ITEM_REPORT_CHANGE (1<<1) #define ITEM_REPORT_SIZE (1<<2) /* regular files only */ #define ITEM_REPORT_TIMEFAIL (1<<2) /* symlinks only */ -@@ -647,6 +649,7 @@ extern int file_extra_cnt; +@@ -651,6 +653,7 @@ extern int file_extra_cnt; extern int inc_recurse; extern int uid_ndx; extern int gid_ndx; @@ -363,7 +363,7 @@ diff --git a/rsync.h b/rsync.h extern int fileflags_ndx; extern int acls_ndx; extern int xattrs_ndx; -@@ -654,6 +657,7 @@ extern int xattrs_ndx; +@@ -658,6 +661,7 @@ extern int xattrs_ndx; #define FILE_STRUCT_LEN (offsetof(struct file_struct, basename)) #define EXTRA_LEN (sizeof (union file_extras)) #define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN) @@ -371,7 +371,7 @@ diff --git a/rsync.h b/rsync.h #define DEV_EXTRA_CNT 2 #define DIRNODE_EXTRA_CNT 3 #define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN) -@@ -912,6 +916,7 @@ typedef struct { +@@ -916,6 +920,7 @@ typedef struct { typedef struct { STRUCT_STAT st; diff --git a/cvs-entries.diff b/cvs-entries.diff index 4da813e..0fb1fbe 100644 --- a/cvs-entries.diff +++ b/cvs-entries.diff @@ -88,7 +88,7 @@ diff --git a/exclude.c b/exclude.c diff --git a/rsync.h b/rsync.h --- a/rsync.h +++ b/rsync.h -@@ -148,6 +148,7 @@ +@@ -149,6 +149,7 @@ #define XFLG_ANCHORED2ABS (1<<2) /* leading slash indicates absolute */ #define XFLG_ABS_IF_SLASH (1<<3) /* leading or interior slash is absolute */ #define XFLG_DIR2WILD3 (1<<4) /* dir/ match gets trailing *** added */ diff --git a/db.diff b/db.diff new file mode 100644 index 0000000..6df344c --- /dev/null +++ b/db.diff @@ -0,0 +1,1215 @@ +Added some DB-access routines to help rsync keep extra filesystem info +about the files it is dealing with. This adds both the --db=CONFIG_FILE +option and the "db config" daemon parameter. + +For the moment this only adds checksum caching when the --checksum option +is used. Future improvments may include: + + - Updating of MD5 checksums when transferring any file, even w/o -c. + + - Caching of path info that allows for the finding of files to use for + moving/linking/copying/alternate-basis-use. + + - Extend DB support beyond MySQL and SQLite (PostgreSQL?). + +To use this patch, run these commands for a successful build: + + patch -p1 st_size; + md_context m; + int32 remainder; + int fd; +@@ -114,7 +115,7 @@ void file_checksum(char *fname, char *sum, OFF_T size) + if (fd == -1) + return; + +- buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK); ++ buf = map_file(fd, len, MAX_MAP_SIZE, CSUM_CHUNK); + + if (protocol_version >= 30) { + md5_begin(&m); +@@ -148,6 +149,9 @@ void file_checksum(char *fname, char *sum, OFF_T size) + mdfour_result(&m, (uchar *)sum); + } + ++ if (use_db) ++ db_set_checksum(fname, st_p, sum); ++ + close(fd); + unmap_file(buf); + } +diff --git a/cleanup.c b/cleanup.c +--- a/cleanup.c ++++ b/cleanup.c +@@ -27,6 +27,7 @@ extern int am_daemon; + extern int io_error; + extern int keep_partial; + extern int got_xfer_error; ++extern int use_db; + extern char *partial_dir; + extern char *logfile_name; + +@@ -124,6 +125,12 @@ NORETURN void _exit_cleanup(int code, const char *file, int line) + /* FALLTHROUGH */ + #include "case_N.h" + ++ if (use_db) ++ db_disconnect(); ++ ++ /* FALLTHROUGH */ ++#include "case_N.h" ++ + if (cleanup_child_pid != -1) { + int status; + int pid = wait_process(cleanup_child_pid, &status, WNOHANG); +diff --git a/clientserver.c b/clientserver.c +--- a/clientserver.c ++++ b/clientserver.c +@@ -42,6 +42,7 @@ extern int numeric_ids; + extern int filesfrom_fd; + extern int remote_protocol; + extern int protocol_version; ++extern int always_checksum; + extern int io_timeout; + extern int no_detach; + extern int write_batch; +@@ -49,6 +50,7 @@ extern int default_af_hint; + extern int logfile_format_has_i; + extern int logfile_format_has_o_or_i; + extern mode_t orig_umask; ++extern char *db_config; + extern char *bind_address; + extern char *sockopts; + extern char *config_file; +@@ -782,6 +784,12 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) + } else if (am_root < 0) /* Treat --fake-super from client as --super. */ + am_root = 2; + ++ db_config = lp_db_config(i); ++ if (!*db_config || (!always_checksum && protocol_version < 30)) ++ db_config = NULL; ++ else ++ db_read_config(FLOG, db_config); ++ + if (filesfrom_fd == 0) + filesfrom_fd = f_in; + +diff --git a/configure.in b/configure.in +--- a/configure.in ++++ b/configure.in +@@ -969,6 +969,8 @@ if test x"$enable_acl_support" = x"no" -o x"$enable_xattr_support" = x"no" -o x" + fi + fi + ++LIBS="$LIBS -lmysqlclient -lsqlite3" ++ + case "$CC" in + ' checker'*|checker*) + AC_DEFINE(FORCE_FD_ZERO_MEMSET, 1, [Used to make "checker" understand that FD_ZERO() clears memory.]) +diff --git a/db.c b/db.c +new file mode 100644 +--- /dev/null ++++ b/db.c +@@ -0,0 +1,557 @@ ++/* ++ * Routines to access extended file info via DB. ++ * ++ * Copyright (C) 2008 Wayne Davison ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, visit the http://fsf.org website. ++ */ ++ ++#include "rsync.h" ++#include "ifuncs.h" ++ ++#define USE_MYSQL ++#define USE_SQLITE ++ ++#ifdef USE_MYSQL ++#include ++#include ++#endif ++#ifdef USE_SQLITE ++#include ++#endif ++ ++extern int protocol_version; ++extern int checksum_len; ++ ++#define DB_TYPE_NONE 0 ++#define DB_TYPE_MYSQL 1 ++#define DB_TYPE_SQLITE 2 ++ ++int use_db = DB_TYPE_NONE; ++ ++static const char *dbhost = NULL, *dbuser = NULL, *dbpass = NULL, *dbname = NULL; ++static unsigned int dbport = 0; ++ ++static union { ++#ifdef USE_MYSQL ++ MYSQL *mysql; ++#endif ++#ifdef USE_SQLITE ++ sqlite3 *sqlite; ++#endif ++ void *all; ++} dbh; ++ ++#define SEL_DEV 0 ++#define SEL_SUM 1 ++#define REP_SUM 2 ++#define MAX_PREP_CNT 3 ++ ++static union { ++#ifdef USE_MYSQL ++ MYSQL_STMT *mysql; ++#endif ++#ifdef USE_SQLITE ++ sqlite3_stmt *sqlite; ++#endif ++ void *all; ++} statements[MAX_PREP_CNT]; ++ ++static int md_num; ++static enum logcode log_code; ++ ++static unsigned int bind_disk_id; ++static unsigned long long bind_devno, bind_ino, bind_size, bind_mtime, bind_ctime; ++static char bind_thishost[256], bind_sum[MAX_DIGEST_LEN]; ++static int bind_thishost_len; ++ ++static unsigned int prior_disk_id = 0; ++static unsigned long long prior_devno = 0; ++ ++int db_read_config(enum logcode code, const char *config_file) ++{ ++ char buf[2048], *cp; ++ FILE *fp; ++ int lineno = 0; ++ ++ log_code = code; ++ ++ bind_thishost_len = strlcpy(bind_thishost, "localhost", sizeof bind_thishost); ++ ++ if (!(fp = fopen(config_file, "r"))) { ++ rsyserr(log_code, errno, "unable to open %s", config_file); ++ return 0; ++ } ++ while (fgets(buf, sizeof buf, fp)) { ++ lineno++; ++ if ((cp = strchr(buf, '#')) == NULL ++ && (cp = strchr(buf, '\r')) == NULL ++ && (cp = strchr(buf, '\n')) == NULL) ++ cp = buf + strlen(buf); ++ while (cp != buf && isSpace(cp-1)) cp--; ++ *cp = '\0'; ++ ++ if (!*buf) ++ continue; ++ ++ if (!(cp = strchr(buf, ':'))) ++ goto invalid_line; ++ *cp++ = '\0'; ++ ++ while (isSpace(cp)) cp++; ++ if (strcasecmp(buf, "dbhost") == 0) ++ dbhost = strdup(cp); ++ else if (strcasecmp(buf, "dbuser") == 0) ++ dbuser = strdup(cp); ++ else if (strcasecmp(buf, "dbpass") == 0) ++ dbpass = strdup(cp); ++ else if (strcasecmp(buf, "dbname") == 0) ++ dbname = strdup(cp); ++ else if (strcasecmp(buf, "dbport") == 0) ++ dbport = atoi(cp); ++ else if (strcasecmp(buf, "thishost") == 0) ++ bind_thishost_len = strlcpy(bind_thishost, cp, sizeof bind_thishost); ++ else if (strcasecmp(buf, "dbtype") == 0) { ++#ifdef USE_MYSQL ++ if (strcasecmp(cp, "mysql") == 0) { ++ use_db = DB_TYPE_MYSQL; ++ continue; ++ } ++#endif ++#ifdef USE_SQLITE ++ if (strcasecmp(cp, "sqlite") == 0) { ++ use_db = DB_TYPE_SQLITE; ++ continue; ++ } ++#endif ++ rprintf(log_code, ++ "Unsupported dbtype on line #%d in %s.\n", ++ lineno, config_file); ++ use_db = DB_TYPE_NONE; ++ return 0; ++ } else { ++ invalid_line: ++ rprintf(log_code, "Invalid line #%d in %s\n", ++ lineno, config_file); ++ use_db = DB_TYPE_NONE; ++ return 0; ++ } ++ } ++ fclose(fp); ++ ++ if (bind_thishost_len >= (int)sizeof bind_thishost) ++ bind_thishost_len = sizeof bind_thishost - 1; ++ ++ if (!use_db || !dbname) { ++ rprintf(log_code, "Please specify at least dbtype and dbname in %s.\n", config_file); ++ use_db = DB_TYPE_NONE; ++ return 0; ++ } ++ ++ md_num = protocol_version >= 30 ? 5 : 4; ++ ++ return 1; ++} ++ ++#ifdef USE_MYSQL ++static MYSQL_STMT *prepare_mysql(MYSQL_BIND *binds, int bind_cnt, const char *fmt, ...) ++{ ++ va_list ap; ++ char *query; ++ int qlen, param_cnt; ++ MYSQL_STMT *stmt = mysql_stmt_init(dbh.mysql); ++ ++ if (stmt == NULL) ++ out_of_memory("prepare_mysql"); ++ ++ va_start(ap, fmt); ++ qlen = vasprintf(&query, fmt, ap); ++ va_end(ap); ++ if (qlen < 0) ++ out_of_memory("prepare_mysql"); ++ ++ if (mysql_stmt_prepare(stmt, query, qlen) != 0) { ++ rprintf(log_code, "Prepare failed: %s\n", mysql_stmt_error(stmt)); ++ return NULL; ++ } ++ free(query); ++ ++ if ((param_cnt = mysql_stmt_param_count(stmt)) != bind_cnt) { ++ rprintf(log_code, "Parameters in statement = %d, bind vars = %d\n", ++ param_cnt, bind_cnt); ++ return NULL; ++ } ++ if (bind_cnt) ++ mysql_stmt_bind_param(stmt, binds); ++ ++ return stmt; ++} ++#endif ++ ++#ifdef USE_MYSQL ++static int db_connect_mysql(void) ++{ ++ MYSQL_BIND binds[10]; ++ ++ if (!(dbh.mysql = mysql_init(NULL))) ++ out_of_memory("db_read_config"); ++ ++ if (!mysql_real_connect(dbh.mysql, dbhost, dbuser, dbpass, dbname, dbport, NULL, 0)) ++ return 0; ++ ++ memset(binds, 0, sizeof binds); ++ binds[0].buffer_type = MYSQL_TYPE_LONGLONG; ++ binds[0].buffer = &bind_devno; ++ binds[1].buffer_type = MYSQL_TYPE_STRING; ++ binds[1].buffer = &bind_thishost; ++ binds[1].buffer_length = bind_thishost_len; ++ statements[SEL_DEV].mysql = prepare_mysql(binds, 2, ++ "SELECT disk_id" ++ " FROM disk" ++ " WHERE devno = ? AND host = ? AND mounted = 1"); ++ if (!statements[SEL_DEV].mysql) ++ return 0; ++ ++ memset(binds, 0, sizeof binds); ++ binds[0].buffer_type = MYSQL_TYPE_LONG; ++ binds[0].buffer = &bind_disk_id; ++ binds[1].buffer_type = MYSQL_TYPE_LONGLONG; ++ binds[1].buffer = &bind_ino; ++ binds[2].buffer_type = MYSQL_TYPE_LONGLONG; ++ binds[2].buffer = &bind_size; ++ binds[3].buffer_type = MYSQL_TYPE_LONGLONG; ++ binds[3].buffer = &bind_mtime; ++ binds[4].buffer_type = MYSQL_TYPE_LONGLONG; ++ binds[4].buffer = &bind_ctime; ++ statements[SEL_SUM].mysql = prepare_mysql(binds, 5, ++ "SELECT checksum" ++ " FROM inode_map" ++ " WHERE disk_id = ? AND ino = ? AND sum_type = %d" ++ " AND size = ? AND mtime = ? AND ctime = ?", ++ md_num); ++ if (!statements[SEL_SUM].mysql) ++ return 0; ++ ++ memset(binds, 0, sizeof binds); ++ binds[0].buffer_type = MYSQL_TYPE_LONG; ++ binds[0].buffer = &bind_disk_id; ++ binds[1].buffer_type = MYSQL_TYPE_LONGLONG; ++ binds[1].buffer = &bind_ino; ++ binds[2].buffer_type = binds[6].buffer_type = MYSQL_TYPE_LONGLONG; ++ binds[2].buffer = binds[6].buffer = &bind_size; ++ binds[3].buffer_type = binds[7].buffer_type = MYSQL_TYPE_LONGLONG; ++ binds[3].buffer = binds[7].buffer = &bind_mtime; ++ binds[4].buffer_type = binds[8].buffer_type = MYSQL_TYPE_LONGLONG; ++ binds[4].buffer = binds[8].buffer = &bind_ctime; ++ binds[5].buffer_type = binds[9].buffer_type = MYSQL_TYPE_BLOB; ++ binds[5].buffer = binds[9].buffer = &bind_sum; ++ binds[5].buffer_length = binds[9].buffer_length = checksum_len; ++ statements[REP_SUM].mysql = prepare_mysql(binds, 10, ++ "INSERT INTO inode_map" ++ " SET disk_id = ?, ino = ?, sum_type = %d," ++ " size = ?, mtime = ?, ctime = ?, checksum = ?" ++ " ON DUPLICATE KEY" ++ " UPDATE size = ?, mtime = ?, ctime = ?, checksum = ?", ++ md_num, md_num); ++ if (!statements[REP_SUM].mysql) ++ return 0; ++ ++ return 1; ++} ++#endif ++ ++#ifdef USE_SQLITE ++static int db_connect_sqlite(void) ++{ ++ char *sql; ++ ++#if 0 ++ if (sqlite3_open_v2(dbname, &dbh.sqlite, SQLITE_OPEN_READWRITE, NULL) != 0) ++ return 0; ++#else ++ if (sqlite3_open(dbname, &dbh.sqlite) != 0) ++ return 0; ++#endif ++ ++ sql = "SELECT disk_id" ++ " FROM disk" ++ " WHERE devno = ? AND host = ? AND mounted = 1"; ++ if (sqlite3_prepare_v2(dbh.sqlite, sql, -1, &statements[SEL_DEV].sqlite, NULL) != 0) ++ return 0; ++ ++ if (asprintf(&sql, ++ "SELECT checksum" ++ " FROM inode_map" ++ " WHERE disk_id = ? AND ino = ? AND sum_type = %d" ++ " AND size = ? AND mtime = ? AND ctime = ?", ++ md_num) < 0 ++ || sqlite3_prepare_v2(dbh.sqlite, sql, -1, &statements[SEL_SUM].sqlite, NULL) != 0) ++ return 0; ++ free(sql); ++ ++ if (asprintf(&sql, ++ "INSERT OR REPLACE INTO inode_map" ++ " (disk_id, ino, sum_type, size, mtime, ctime, checksum)" ++ " VALUES(?, ?, %d, ?, ?, ?, ?)", ++ md_num) < 0 ++ || sqlite3_prepare_v2(dbh.sqlite, sql, -1, &statements[REP_SUM].sqlite, NULL) != 0) ++ return 0; ++ free(sql); ++ ++ return 1; ++} ++#endif ++ ++int db_connect(void) ++{ ++ switch (use_db) { ++#ifdef USE_MYSQL ++ case DB_TYPE_MYSQL: ++ if (db_connect_mysql()) ++ return 1; ++ break; ++#endif ++#ifdef USE_SQLITE ++ case DB_TYPE_SQLITE: ++ if (db_connect_sqlite()) ++ return 1; ++ break; ++#endif ++ } ++ ++ rprintf(log_code, "Unable to connect to DB\n"); ++ db_disconnect(); ++ use_db = DB_TYPE_NONE; ++ ++ return 0; ++} ++ ++void db_disconnect(void) ++{ ++ int ndx; ++ ++ if (!dbh.all) ++ return; ++ ++ for (ndx = 0; ndx < MAX_PREP_CNT; ndx++) { ++ if (statements[ndx].all) { ++ switch (use_db) { ++#ifdef USE_MYSQL ++ case DB_TYPE_MYSQL: ++ mysql_stmt_close(statements[ndx].mysql); ++ break; ++#endif ++#ifdef USE_SQLITE ++ case DB_TYPE_SQLITE: ++ sqlite3_finalize(statements[ndx].sqlite); ++ break; ++#endif ++ } ++ statements[ndx].all = NULL; ++ } ++ } ++ ++ switch (use_db) { ++#ifdef USE_MYSQL ++ case DB_TYPE_MYSQL: ++ mysql_close(dbh.mysql); ++ break; ++#endif ++#ifdef USE_SQLITE ++ case DB_TYPE_SQLITE: ++ sqlite3_close(dbh.sqlite); ++ break; ++#endif ++ } ++ ++ dbh.all = NULL; ++} ++ ++static MYSQL_STMT *exec_mysql(int ndx) ++{ ++ MYSQL_STMT *stmt = statements[ndx].mysql; ++ int rc; ++ ++ if ((rc = mysql_stmt_execute(stmt)) == CR_SERVER_LOST) { ++ db_disconnect(); ++ if (db_connect()) { ++ stmt = statements[ndx].mysql; ++ rc = mysql_stmt_execute(stmt); ++ } ++ } ++ if (rc != 0) { ++ rprintf(log_code, "SQL execute failed: %s\n", mysql_stmt_error(stmt)); ++ return NULL; ++ } ++ ++ return stmt; ++} ++ ++static int fetch_mysql(MYSQL_BIND *binds, int bind_cnt, int ndx) ++{ ++ unsigned long length[32]; ++ my_bool is_null[32], error[32]; ++ MYSQL_STMT *stmt; ++ int i, rc; ++ ++ if (bind_cnt > 32) ++ exit_cleanup(RERR_UNSUPPORTED); ++ ++ if ((stmt = exec_mysql(ndx)) == NULL) ++ return 0; ++ ++ for (i = 0; i < bind_cnt; i++) { ++ binds[i].is_null = &is_null[i]; ++ binds[i].length = &length[i]; ++ binds[i].error = &error[i]; ++ } ++ mysql_stmt_bind_result(stmt, binds); ++ ++ if ((rc = mysql_stmt_fetch(stmt)) != 0) { ++ if (rc != MYSQL_NO_DATA) { ++ rprintf(log_code, "SELECT fetch failed: %s\n", ++ mysql_stmt_error(stmt)); ++ } ++ mysql_stmt_free_result(stmt); ++ return 0; ++ } ++ ++ mysql_stmt_free_result(stmt); ++ ++ return is_null[0] ? 0 : 1; ++} ++ ++static void get_disk_id(unsigned long long devno) ++{ ++ switch (use_db) { ++#ifdef USE_MYSQL ++ case DB_TYPE_MYSQL: { ++ MYSQL_BIND binds[1]; ++ ++ bind_devno = devno; /* The one variable SEL_DEV input value. */ ++ ++ /* Bind where to put the output. */ ++ binds[0].buffer_type = MYSQL_TYPE_LONG; ++ binds[0].buffer = &prior_disk_id; ++ if (!fetch_mysql(binds, 1, SEL_DEV)) ++ prior_disk_id = 0; ++ break; ++ } ++#endif ++#ifdef USE_SQLITE ++ case DB_TYPE_SQLITE: { ++ sqlite3_stmt *stmt = statements[SEL_DEV].sqlite; ++ sqlite3_bind_int64(stmt, 1, devno); ++ sqlite3_bind_text(stmt, 2, bind_thishost, bind_thishost_len, SQLITE_STATIC); ++ if (sqlite3_step(stmt) == SQLITE_ROW) ++ prior_disk_id = sqlite3_column_int(stmt, 0); ++ else ++ prior_disk_id = 0; ++ sqlite3_reset(stmt); ++ break; ++ } ++#endif ++ } ++ ++ prior_devno = devno; ++} ++ ++int db_get_checksum(UNUSED(const char *fname), const STRUCT_STAT *st_p, char *sum) ++{ ++ if (prior_devno != st_p->st_dev) ++ get_disk_id(st_p->st_dev); ++ if (prior_disk_id == 0) ++ return 0; ++ ++ switch (use_db) { ++#ifdef USE_MYSQL ++ case DB_TYPE_MYSQL: { ++ MYSQL_BIND binds[1]; ++ ++ bind_disk_id = prior_disk_id; ++ bind_ino = st_p->st_ino; ++ bind_size = st_p->st_size; ++ bind_mtime = st_p->st_mtime; ++ bind_ctime = st_p->st_ctime; ++ ++ binds[0].buffer_type = MYSQL_TYPE_BLOB; ++ binds[0].buffer = sum; ++ binds[0].buffer_length = checksum_len; ++ return fetch_mysql(binds, 1, SEL_SUM); ++ } ++#endif ++#ifdef USE_SQLITE ++ case DB_TYPE_SQLITE: { ++ sqlite3_stmt *stmt = statements[SEL_SUM].sqlite; ++ sqlite3_bind_int(stmt, 1, prior_disk_id); ++ sqlite3_bind_int64(stmt, 2, st_p->st_ino); ++ sqlite3_bind_int64(stmt, 3, st_p->st_size); ++ sqlite3_bind_int64(stmt, 4, st_p->st_mtime); ++ sqlite3_bind_int64(stmt, 5, st_p->st_ctime); ++ if (sqlite3_step(stmt) == SQLITE_ROW) { ++ int len = sqlite3_column_bytes(stmt, 0); ++ if (len > MAX_DIGEST_LEN) ++ len = MAX_DIGEST_LEN; ++ memcpy(sum, sqlite3_column_blob(stmt, 0), len); ++ sqlite3_reset(stmt); ++ return 1; ++ } ++ sqlite3_reset(stmt); ++ return 0; ++ } ++#endif ++ } ++ ++ return 0; ++} ++ ++int db_set_checksum(UNUSED(const char *fname), const STRUCT_STAT *st_p, const char *sum) ++{ ++ if (prior_devno != st_p->st_dev) ++ get_disk_id(st_p->st_dev); ++ if (prior_disk_id == 0) ++ return 0; ++ ++ switch (use_db) { ++#ifdef USE_MYSQL ++ case DB_TYPE_MYSQL: { ++ bind_disk_id = prior_disk_id; ++ bind_ino = st_p->st_ino; ++ bind_size = st_p->st_size; ++ bind_mtime = st_p->st_mtime; ++ bind_ctime = st_p->st_ctime; ++ memcpy(bind_sum, sum, checksum_len); ++ ++ return exec_mysql(REP_SUM) != NULL; ++ } ++#endif ++#ifdef USE_SQLITE ++ case DB_TYPE_SQLITE: { ++ int rc; ++ sqlite3_stmt *stmt = statements[REP_SUM].sqlite; ++ sqlite3_bind_int(stmt, 1, prior_disk_id); ++ sqlite3_bind_int64(stmt, 2, st_p->st_ino); ++ sqlite3_bind_int64(stmt, 3, st_p->st_size); ++ sqlite3_bind_int64(stmt, 4, st_p->st_mtime); ++ sqlite3_bind_int64(stmt, 5, st_p->st_ctime); ++ sqlite3_bind_blob(stmt, 6, sum, checksum_len, SQLITE_TRANSIENT); ++ rc = sqlite3_step(stmt); ++ sqlite3_reset(stmt); ++ return rc == SQLITE_DONE; ++ } ++#endif ++ } ++ ++ return 0; ++} +diff --git a/flist.c b/flist.c +--- a/flist.c ++++ b/flist.c +@@ -54,6 +54,7 @@ extern int preserve_devices; + extern int preserve_specials; + extern int uid_ndx; + extern int gid_ndx; ++extern int use_db; + extern int eol_nulls; + extern int relative_paths; + extern int implied_dirs; +@@ -1235,14 +1236,16 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, + memcpy(bp + basename_len, linkname, linkname_len); + #endif + +- if (always_checksum && am_sender && S_ISREG(st.st_mode)) +- file_checksum(thisname, tmp_sum, st.st_size); +- + if (am_sender) + F_PATHNAME(file) = pathname; + else if (!pool) + F_DEPTH(file) = extra_len / EXTRA_LEN; + ++ if (always_checksum && am_sender && S_ISREG(st.st_mode)) { ++ if (!use_db || !db_get_checksum(thisname, &st, tmp_sum)) ++ file_checksum(thisname, &st, tmp_sum); ++ } ++ + /* This code is only used by the receiver when it is building + * a list of files for a delete pass. */ + if (keep_dirlinks && linkname_len && flist) { +@@ -1858,6 +1861,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) + | (eol_nulls || reading_remotely ? RL_EOL_NULLS : 0); + int implied_dot_dir = 0; + ++ if (use_db) ++ db_connect(); ++ + rprintf(FLOG, "building file list\n"); + if (show_filelist_p()) + start_filelist_progress("building file list"); +diff --git a/generator.c b/generator.c +--- a/generator.c ++++ b/generator.c +@@ -58,6 +58,7 @@ extern int update_only; + extern int ignore_existing; + extern int ignore_non_existing; + extern int inplace; ++extern int use_db; + extern int append_mode; + extern int make_backups; + extern int csum_length; +@@ -718,7 +719,8 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st) + of the file time to determine whether to sync */ + if (always_checksum > 0 && S_ISREG(st->st_mode)) { + char sum[MAX_DIGEST_LEN]; +- file_checksum(fn, sum, st->st_size); ++ if (!use_db || !db_get_checksum(fn, st, sum)) ++ file_checksum(fn, st, sum); + return memcmp(sum, F_SUM(file), checksum_len) == 0; + } + +@@ -2161,6 +2163,9 @@ void generate_files(int f_out, const char *local_name) + : "enabled"); + } + ++ if (use_db && always_checksum) ++ db_connect(); ++ + /* Since we often fill up the outgoing socket and then just sit around + * waiting for the other 2 processes to do their thing, we don't want + * to exit on a timeout. If the data stops flowing, the receiver will +diff --git a/loadparm.c b/loadparm.c +--- a/loadparm.c ++++ b/loadparm.c +@@ -126,6 +126,7 @@ typedef struct + char *auth_users; + char *charset; + char *comment; ++ char *db_config; + char *dont_compress; + char *exclude; + char *exclude_from; +@@ -177,6 +178,7 @@ static service sDefault = + /* auth_users; */ NULL, + /* charset; */ NULL, + /* comment; */ NULL, ++ /* db_config; */ NULL, + /* dont_compress; */ DEFAULT_DONT_COMPRESS, + /* exclude; */ NULL, + /* exclude_from; */ NULL, +@@ -307,6 +309,7 @@ static struct parm_struct parm_table[] = + {"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL,0}, + {"charset", P_STRING, P_LOCAL, &sDefault.charset, NULL,0}, + {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL,0}, ++ {"db config", P_STRING, P_LOCAL, &sDefault.db_config, NULL,0}, + {"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress, NULL,0}, + {"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from, NULL,0}, + {"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL,0}, +@@ -400,6 +403,7 @@ FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port) + FN_LOCAL_STRING(lp_auth_users, auth_users) + FN_LOCAL_STRING(lp_charset, charset) + FN_LOCAL_STRING(lp_comment, comment) ++FN_LOCAL_STRING(lp_db_config, db_config) + FN_LOCAL_STRING(lp_dont_compress, dont_compress) + FN_LOCAL_STRING(lp_exclude, exclude) + FN_LOCAL_STRING(lp_exclude_from, exclude_from) +diff --git a/main.c b/main.c +--- a/main.c ++++ b/main.c +@@ -49,6 +49,7 @@ extern int copy_unsafe_links; + extern int keep_dirlinks; + extern int preserve_hard_links; + extern int protocol_version; ++extern int always_checksum; + extern int file_total; + extern int recurse; + extern int xfer_dirs; +@@ -73,6 +74,7 @@ extern char *partial_dir; + extern char *dest_option; + extern char *basis_dir[]; + extern char *rsync_path; ++extern char *db_config; + extern char *shell_cmd; + extern char *batch_name; + extern char *password_file; +@@ -1482,6 +1484,9 @@ int main(int argc,char *argv[]) + exit_cleanup(RERR_SYNTAX); + } + ++ if (db_config && (always_checksum || protocol_version >= 30)) ++ db_read_config(FERROR, db_config); ++ + if (am_server) { + set_nonblocking(STDIN_FILENO); + set_nonblocking(STDOUT_FILENO); +diff --git a/options.c b/options.c +--- a/options.c ++++ b/options.c +@@ -92,6 +92,7 @@ int use_qsort = 0; + char *files_from = NULL; + int filesfrom_fd = -1; + char *filesfrom_host = NULL; ++char *db_config = NULL; + int eol_nulls = 0; + int protect_args = 0; + int human_readable = 0; +@@ -321,6 +322,7 @@ void usage(enum logcode F) + rprintf(F," -q, --quiet suppress non-error messages\n"); + rprintf(F," --no-motd suppress daemon-mode MOTD (see manpage caveat)\n"); + rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n"); ++ rprintf(F," --db=CONFIG_FILE specify a config file for FS DB\n"); + rprintf(F," -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)\n"); + rprintf(F," --no-OPTION turn off an implied OPTION (e.g. --no-D)\n"); + rprintf(F," -r, --recursive recurse into directories\n"); +@@ -579,6 +581,7 @@ static struct poptOption long_options[] = { + {"checksum", 'c', POPT_ARG_VAL, &always_checksum, 1, 0, 0 }, + {"no-checksum", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 }, + {"no-c", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 }, ++ {"db", 0, POPT_ARG_STRING, &db_config, 0, 0, 0 }, + {"block-size", 'B', POPT_ARG_LONG, &block_size, 0, 0, 0 }, + {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 }, + {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 }, +diff --git a/pipe.c b/pipe.c +--- a/pipe.c ++++ b/pipe.c +@@ -26,6 +26,10 @@ extern int am_sender; + extern int am_server; + extern int blocking_io; + extern int filesfrom_fd; ++extern int always_checksum; ++extern int protocol_version; ++extern int use_db; ++extern char *db_config; + extern mode_t orig_umask; + extern char *logfile_name; + extern int remote_option_cnt; +@@ -141,6 +145,9 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out, + logfile_close(); + } + ++ use_db = 0; ++ db_config = NULL; ++ + if (remote_option_cnt) { + int rc = remote_option_cnt + 1; + const char **rv = remote_options; +@@ -148,6 +155,8 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out, + option_error(); + exit_cleanup(RERR_SYNTAX); + } ++ if (db_config && (always_checksum || protocol_version >= 30)) ++ db_read_config(FERROR, db_config); + } + + if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || +diff --git a/receiver.c b/receiver.c +--- a/receiver.c ++++ b/receiver.c +@@ -43,11 +43,13 @@ extern int basis_dir_cnt; + extern int make_backups; + extern int cleanup_got_literal; + extern int remove_source_files; ++extern int always_checksum; + extern int append_mode; + extern int sparse_files; + extern int keep_partial; + extern int checksum_seed; + extern int inplace; ++extern int use_db; + extern int delay_updates; + extern mode_t orig_umask; + extern struct stats stats; +@@ -399,6 +401,9 @@ int recv_files(int f_in, char *local_name) + if (verbose > 2) + rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used); + ++ if (use_db && !always_checksum) ++ db_connect(); ++ + if (delay_updates) + delayed_bits = bitbag_create(cur_flist->used + 1); + +diff --git a/support/dbupdate b/support/dbupdate +new file mode 100755 +--- /dev/null ++++ b/support/dbupdate +@@ -0,0 +1,281 @@ ++#!/usr/bin/perl -w ++use strict; ++ ++use DBI; ++use Getopt::Long; ++use Cwd qw(abs_path cwd); ++use Digest::MD4; ++use Digest::MD5; ++ ++my $MOUNT_FILE = '/etc/mtab'; ++ ++&Getopt::Long::Configure('bundling'); ++&usage if !&GetOptions( ++ 'db=s' => \( my $db_config ), ++ 'mounts|m' => \( my $update_mounts ), ++ 'recurse|r' => \( my $recurse_opt ), ++ 'check|c' => \( my $check_opt ), ++ 'verbose|v+' => \( my $verbosity = 0 ), ++ 'help|h' => \( my $help_opt ), ++); ++&usage if $help_opt || !defined $db_config; ++ ++my %config; ++open(IN, '<', $db_config) or die "Unable to open $db_config: $!\n"; ++while () { ++ s/[#\r\n].*//s; ++ next if /^$/; ++ my($key, $val) = /^(\S+):\s*(.*)/ or die "Unable to parse line $. of $db_config\n"; ++ $config{$key} = $val; ++} ++close IN; ++ ++die "You must define at least dbtype and dbname in $db_config\n" ++ unless defined $config{'dbtype'} && defined $config{'dbname'}; ++ ++my $thishost = $config{'thishost'} || 'localhost'; ++ ++my $connect = 'DBI:' . $config{'dbtype'} . ':database=' . $config{'dbname'}; ++$connect =~ s/:database=/:dbname=/ if $config{'dbtype'} eq 'SQLite'; ++$connect .= ';host=' . $config{'dbhost'} if defined $config{'dbhost'}; ++$connect .= ';port=' . $config{'dbport'} if defined $config{'dbport'}; ++ ++my $dbh = DBI->connect($connect, $config{'dbuser'}, $config{'dbpass'}) ++ or die "DB connection failed\n"; ++ ++END { ++ $dbh->disconnect if defined $dbh; ++} ++ ++my $sel_disk_H = $dbh->prepare(" ++ SELECT disk_id, devno, mounted, comment ++ FROM disk ++ WHERE host = ? ++ ") or die $dbh->errstr; ++ ++my $ins_disk_H = $dbh->prepare(" ++ INSERT INTO disk ++ (devno, host, mounted, comment) ++ VALUES(?, ?, ?, ?) ++ ") or die $dbh->errstr; ++ ++my $up_disk_H = $dbh->prepare(" ++ UPDATE disk ++ SET mounted = ? ++ WHERE disk_id = ? ++ ") or die $dbh->errstr; ++ ++my $row_id = $config{'dbtype'} eq 'SQLite' ? 'ROWID' : 'ID'; ++my $sel_lastid_H = $dbh->prepare(" ++ SELECT LAST_INSERT_$row_id() ++ ") or die $dbh->errstr; ++ ++my $sel_sum_H = $dbh->prepare(" ++ SELECT sum_type, checksum ++ FROM inode_map ++ WHERE disk_id = ? AND ino = ? AND size = ? AND mtime = ? AND ctime = ? ++ ") or die $dbh->errstr; ++ ++my $rep_sum_H = $dbh->prepare(" ++ REPLACE INTO inode_map ++ (disk_id, ino, size, mtime, ctime, sum_type, checksum) ++ VALUES(?, ?, ?, ?, ?, ?, ?) ++ ") or die $dbh->errstr; ++ ++my %mounts; ++if ($update_mounts) { ++ open(IN, $MOUNT_FILE) or die "Unable to open $MOUNT_FILE: $!\n"; ++ while () { ++ my($devname, $mnt) = (split)[0,1]; ++ next unless $devname =~ m#^/dev#; ++ my($devno) = (stat($mnt))[0]; ++ if (!defined $devno) { ++ warn "Unable to stat $mnt: $!\n"; ++ next; ++ } ++ $mounts{$devno} = "$devname on $mnt"; ++ } ++ close IN; ++} ++ ++my %disk_id; ++$sel_disk_H->execute($thishost); ++while (my($disk_id, $devno, $mounted, $comment) = $sel_disk_H->fetchrow_array) { ++ if ($update_mounts) { ++ if (defined $mounts{$devno}) { ++ if ($comment ne $mounts{$devno}) { ++ if ($mounted) { ++ $up_disk_H->execute(0, $disk_id); ++ } ++ next; ++ } ++ if (!$mounted) { ++ $up_disk_H->execute(1, $disk_id); ++ } ++ } else { ++ if ($mounted) { ++ $up_disk_H->execute(0, $disk_id); ++ } ++ next; ++ } ++ } else { ++ next unless $mounted; ++ } ++ $disk_id{$devno} = $disk_id; ++} ++$sel_disk_H->finish; ++ ++if ($update_mounts) { ++ while (my($devno, $comment) = each %mounts) { ++ next if $disk_id{$devno}; ++ $ins_disk_H->execute($devno, $thishost, 1, $comment); ++ $sel_lastid_H->execute; ++ ($disk_id{$devno}) = $sel_lastid_H->fetchrow_array; ++ $sel_lastid_H->finish; ++ } ++} ++ ++my $start_dir = cwd(); ++ ++my @dirs = @ARGV; ++@dirs = '.' unless @dirs; ++foreach (@dirs) { ++ $_ = abs_path($_); ++} ++ ++$| = 1; ++ ++my $exit_code = 0; ++ ++my $md4 = Digest::MD4->new; ++my $md5 = Digest::MD5->new; ++ ++while (@dirs) { ++ my $dir = shift @dirs; ++ ++ if (!chdir($dir)) { ++ warn "Unable to chdir to $dir: $!\n"; ++ next; ++ } ++ if (!opendir(DP, '.')) { ++ warn "Unable to opendir $dir: $!\n"; ++ next; ++ } ++ ++ my $reldir = $dir; ++ $reldir =~ s#^$start_dir(/|$)# $1 ? '' : '.' #eo; ++ print "$reldir ... \n" if $verbosity; ++ ++ my @subdirs; ++ while (defined(my $fn = readdir(DP))) { ++ next if $fn =~ /^\.\.?$/ || -l $fn; ++ if (-d _) { ++ push(@subdirs, "$dir/$fn") unless $fn =~ /^(CVS|\.svn|\.git|\.bzr)$/; ++ next; ++ } ++ next unless -f _; ++ ++ my($dev,$ino,$size,$mtime,$ctime) = (stat(_))[0,1,7,9,10]; ++ my $disk_id = $disk_id{$dev} or next; ++ $sel_sum_H->execute($disk_id,$ino,$size,$mtime,$ctime) or die $!; ++ my($sum4, $dbsum4, $sum5, $dbsum5); ++ my $dbsumcnt = 0; ++ while (my($sum_type, $checksum) = $sel_sum_H->fetchrow_array) { ++ if ($sum_type == 4) { ++ $dbsum4 = $checksum; ++ $dbsumcnt++; ++ } elsif ($sum_type == 5) { ++ $dbsum5 = $checksum; ++ $dbsumcnt++; ++ } ++ } ++ $sel_sum_H->finish; ++ ++ next if !$check_opt && $dbsumcnt == 2; ++ ++ if (!$check_opt || $dbsumcnt || $verbosity > 2) { ++ if (!open(IN, $fn)) { ++ print STDERR "Unable to read $fn: $!\n"; ++ next; ++ } ++ ++ while (1) { ++ while (sysread(IN, $_, 64*1024)) { ++ $md4->add($_); ++ $md5->add($_); ++ } ++ $sum4 = $md4->digest; ++ $sum5 = $md5->digest; ++ print ' ', unpack('H*', $sum4), ' ', unpack('H*', $sum5) if $verbosity > 2; ++ print " $fn" if $verbosity > 1; ++ my($ino2,$size2,$mtime2,$ctime2) = (stat(IN))[1,7,9,10]; ++ last if $ino == $ino2 && $size == $size2 && $mtime == $mtime2 && $ctime == $ctime2; ++ $ino = $ino2; ++ $size = $size2; ++ $mtime = $mtime2; ++ $ctime = $ctime2; ++ sysseek(IN, 0, 0); ++ print " REREADING\n" if $verbosity > 1; ++ } ++ ++ close IN; ++ } elsif ($verbosity > 1) { ++ print "_$fn"; ++ } ++ ++ if ($check_opt) { ++ my $dif; ++ if ($dbsumcnt == 0) { ++ $dif = ' --MISSING--'; ++ } else { ++ $dif = ''; ++ if (!defined $dbsum4) { ++ $dif .= ' -NO-MD4-'; ++ } elsif ($sum4 ne $dbsum4) { ++ $dif .= ' -MD4-CHANGED-'; ++ } ++ if (!defined $dbsum5) { ++ $dif .= ' ---NO-MD5---'; ++ } elsif ($sum5 ne $dbsum5) { ++ $dif .= ' -MD5-CHANGED-'; ++ } ++ if ($dif eq '') { ++ print " ====OK====\n" if $verbosity > 1; ++ next; ++ } ++ $dif =~ s/MD4-CHANGED MD5-//; ++ } ++ if ($verbosity < 2) { ++ print $verbosity ? ' ' : "$reldir/"; ++ print $fn; ++ } ++ print $dif, "\n"; ++ $exit_code = 1; ++ } else { ++ print "\n" if $verbosity > 1; ++ $rep_sum_H->execute($disk_id, $ino, $size, $mtime, $ctime, 4, $sum4); ++ $rep_sum_H->execute($disk_id, $ino, $size, $mtime, $ctime, 5, $sum5); ++ } ++ } ++ ++ closedir DP; ++ ++ unshift(@dirs, sort @subdirs) if $recurse_opt; ++} ++ ++exit $exit_code; ++ ++sub usage ++{ ++ die <basename, f->basename); if (diff == 0) { good_match = mid; -@@ -1968,6 +1970,21 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1967,6 +1969,21 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, fnamecmp = partialptr; fnamecmp_type = FNAMECMP_PARTIAL_DIR; statret = 0; diff --git a/detect-renamed.diff b/detect-renamed.diff index 78b14a7..e28ed1d 100644 --- a/detect-renamed.diff +++ b/detect-renamed.diff @@ -71,7 +71,7 @@ diff --git a/flist.c b/flist.c static char empty_sum[MAX_DIGEST_LEN]; static int flist_count_offset; /* for --delete --progress */ static int dir_count = 0; -@@ -298,6 +301,45 @@ static int is_excluded(const char *fname, int is_dir, int filter_level) +@@ -287,6 +290,45 @@ static int is_excluded(const char *fname, int is_dir, int filter_level) return 0; } @@ -117,7 +117,7 @@ diff --git a/flist.c b/flist.c static void send_directory(int f, struct file_list *flist, char *fbuf, int len, int flags); -@@ -2251,6 +2293,25 @@ struct file_list *recv_file_list(int f) +@@ -2259,6 +2301,25 @@ struct file_list *recv_file_list(int f) flist_sort_and_clean(flist, relative_paths); @@ -480,9 +480,9 @@ diff --git a/generator.c b/generator.c + delete_during < 0 ? DEL_NO_DELETIONS : 0); + } else change_local_filter_dir(fname, strlen(fname), F_DEPTH(file)); - } -@@ -1765,8 +1917,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, + goto cleanup; +@@ -1764,8 +1916,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, goto cleanup; } #endif @@ -498,7 +498,7 @@ diff --git a/generator.c b/generator.c rsyserr(FERROR_XFER, stat_errno, "recv_generator: failed to stat %s", full_fname(fname)); goto cleanup; -@@ -2143,6 +2301,12 @@ void generate_files(int f_out, const char *local_name) +@@ -2142,6 +2300,12 @@ void generate_files(int f_out, const char *local_name) if (verbose > 2) rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid()); @@ -511,7 +511,7 @@ diff --git a/generator.c b/generator.c if (delete_before && !solo_file && cur_flist->used > 0) do_delete_pass(); if (delete_during == 2) { -@@ -2153,7 +2317,7 @@ void generate_files(int f_out, const char *local_name) +@@ -2152,7 +2316,7 @@ void generate_files(int f_out, const char *local_name) } do_progress = 0; @@ -520,7 +520,7 @@ diff --git a/generator.c b/generator.c whole_file = 0; if (verbose >= 2) { rprintf(FINFO, "delta-transmission %s\n", -@@ -2192,7 +2356,7 @@ void generate_files(int f_out, const char *local_name) +@@ -2191,7 +2355,7 @@ void generate_files(int f_out, const char *local_name) dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); } else dirdev = MAKEDEV(0, 0); @@ -529,7 +529,7 @@ diff --git a/generator.c b/generator.c } else change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp)); } -@@ -2236,7 +2400,21 @@ void generate_files(int f_out, const char *local_name) +@@ -2235,7 +2399,21 @@ void generate_files(int f_out, const char *local_name) } while ((cur_flist = cur_flist->next) != NULL); if (delete_during) @@ -641,7 +641,7 @@ diff --git a/rsync.yo b/rsync.yo diff --git a/util.c b/util.c --- a/util.c +++ b/util.c -@@ -1112,6 +1112,32 @@ int handle_partial_dir(const char *fname, int create) +@@ -1096,6 +1096,32 @@ int handle_partial_dir(const char *fname, int create) return 1; } diff --git a/downdate.diff b/downdate.diff index 7b922a4..276c98e 100644 --- a/downdate.diff +++ b/downdate.diff @@ -18,7 +18,7 @@ diff --git a/generator.c b/generator.c extern int ignore_existing; extern int ignore_non_existing; extern int inplace; -@@ -1706,6 +1707,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1705,6 +1706,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, goto cleanup; } @@ -32,7 +32,7 @@ diff --git a/generator.c b/generator.c fnamecmp = fname; fnamecmp_type = FNAMECMP_FNAME; -@@ -2053,6 +2061,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo) +@@ -2052,6 +2060,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo) ignore_existing = -ignore_existing; ignore_non_existing = -ignore_non_existing; update_only = -update_only; @@ -40,7 +40,7 @@ diff --git a/generator.c b/generator.c always_checksum = -always_checksum; size_only = -size_only; append_mode = -append_mode; -@@ -2078,6 +2087,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo) +@@ -2077,6 +2086,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo) ignore_existing = -ignore_existing; ignore_non_existing = -ignore_non_existing; update_only = -update_only; diff --git a/fileflags.diff b/fileflags.diff index 80f0d91..ca7c1aa 100644 --- a/fileflags.diff +++ b/fileflags.diff @@ -85,7 +85,7 @@ diff --git a/flist.c b/flist.c extern int uid_ndx; extern int gid_ndx; extern int eol_nulls; -@@ -381,6 +382,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, +@@ -386,6 +387,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, { static time_t modtime; static mode_t mode; @@ -95,7 +95,7 @@ diff --git a/flist.c b/flist.c #ifdef SUPPORT_HARD_LINKS static int64 dev; #endif -@@ -410,6 +414,14 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, +@@ -415,6 +419,14 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, xflags |= XMIT_SAME_MODE; else mode = file->mode; @@ -153,7 +153,7 @@ diff --git a/flist.c b/flist.c if (preserve_uid) F_OWNER(file) = uid; if (preserve_gid) { -@@ -1211,6 +1238,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, +@@ -1222,6 +1249,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32); } file->mode = st.st_mode; @@ -267,7 +267,7 @@ diff --git a/generator.c b/generator.c rsyserr(FERROR_XFER, errno, "failed to modify permissions on %s", full_fname(fname)); -@@ -1500,6 +1532,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1499,6 +1531,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); } @@ -278,7 +278,7 @@ diff --git a/generator.c b/generator.c #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_HLINK_NOT_FIRST(file) -@@ -2012,13 +2048,17 @@ static void touch_up_dirs(struct file_list *flist, int ndx) +@@ -2011,13 +2047,17 @@ static void touch_up_dirs(struct file_list *flist, int ndx) continue; fname = f_name(file, NULL); if (!(file->mode & S_IWUSR)) @@ -566,7 +566,7 @@ diff --git a/rsync.h b/rsync.h /* These flags are used in the live flist data. */ -@@ -151,6 +152,7 @@ +@@ -152,6 +153,7 @@ #define ATTRS_REPORT (1<<0) #define ATTRS_SKIP_MTIME (1<<1) @@ -574,7 +574,7 @@ diff --git a/rsync.h b/rsync.h #define FULL_FLUSH 1 #define NORMAL_FLUSH 0 -@@ -177,6 +179,7 @@ +@@ -178,6 +180,7 @@ #define ITEM_REPORT_GROUP (1<<6) #define ITEM_REPORT_ACL (1<<7) #define ITEM_REPORT_XATTR (1<<8) @@ -582,7 +582,7 @@ diff --git a/rsync.h b/rsync.h #define ITEM_BASIS_TYPE_FOLLOWS (1<<11) #define ITEM_XNAME_FOLLOWS (1<<12) #define ITEM_IS_NEW (1<<13) -@@ -454,6 +457,28 @@ typedef unsigned int size_t; +@@ -458,6 +461,28 @@ typedef unsigned int size_t; #endif #endif @@ -611,7 +611,7 @@ diff --git a/rsync.h b/rsync.h /* Find a variable that is either exactly 32-bits or longer. * If some code depends on 32-bit truncation, it will need to * take special action in a "#if SIZEOF_INT32 > 4" section. */ -@@ -622,6 +647,7 @@ extern int file_extra_cnt; +@@ -626,6 +651,7 @@ extern int file_extra_cnt; extern int inc_recurse; extern int uid_ndx; extern int gid_ndx; @@ -619,7 +619,7 @@ diff --git a/rsync.h b/rsync.h extern int acls_ndx; extern int xattrs_ndx; -@@ -659,6 +685,11 @@ extern int xattrs_ndx; +@@ -663,6 +689,11 @@ extern int xattrs_ndx; /* When the associated option is on, all entries will have these present: */ #define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum #define F_GROUP(f) REQ_EXTRA(f, gid_ndx)->unum diff --git a/ignore-case.diff b/ignore-case.diff index 39437a5..169bf91 100644 --- a/ignore-case.diff +++ b/ignore-case.diff @@ -55,7 +55,7 @@ diff --git a/flist.c b/flist.c extern int ignore_errors; extern int numeric_ids; extern int recurse; -@@ -2688,6 +2689,7 @@ int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2) +@@ -2696,6 +2697,7 @@ int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2) { int dif; const uchar *c1, *c2; @@ -63,7 +63,7 @@ diff --git a/flist.c b/flist.c enum fnc_state state1, state2; enum fnc_type type1, type2; enum fnc_type t_path = protocol_version >= 29 ? t_PATH : t_ITEM; -@@ -2798,7 +2800,15 @@ int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2) +@@ -2806,7 +2808,15 @@ int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2) if (type1 != type2) return type1 == t_PATH ? 1 : -1; } diff --git a/link-by-hash.diff b/link-by-hash.diff index 6c6ad1b..96bea34 100644 --- a/link-by-hash.diff +++ b/link-by-hash.diff @@ -561,7 +561,7 @@ diff --git a/rsync.c b/rsync.c diff --git a/rsync.h b/rsync.h --- a/rsync.h +++ b/rsync.h -@@ -820,6 +820,14 @@ struct stats { +@@ -824,6 +824,14 @@ struct stats { int num_transferred_files; }; diff --git a/openssl-support.diff b/openssl-support.diff index c1ad7f6..51543c3 100644 --- a/openssl-support.diff +++ b/openssl-support.diff @@ -435,7 +435,7 @@ diff --git a/rsync.h b/rsync.h #define SYMLINK_PREFIX "/rsyncd-munged/" #define SYMLINK_PREFIX_LEN ((int)sizeof SYMLINK_PREFIX - 1) -@@ -539,6 +540,11 @@ typedef unsigned int size_t; +@@ -543,6 +544,11 @@ typedef unsigned int size_t; # define SIZEOF_INT64 SIZEOF_OFF_T #endif diff --git a/preallocate.diff b/preallocate.diff index d910772..a2b3868 100644 --- a/preallocate.diff +++ b/preallocate.diff @@ -203,7 +203,7 @@ diff --git a/receiver.c b/receiver.c diff --git a/rsync.h b/rsync.h --- a/rsync.h +++ b/rsync.h -@@ -604,6 +604,13 @@ struct ht_int64_node { +@@ -608,6 +608,13 @@ struct ht_int64_node { #define ACLS_NEED_MASK 1 #endif diff --git a/remote-option.diff b/remote-option.diff index 16975c0..045d314 100644 --- a/remote-option.diff +++ b/remote-option.diff @@ -18,9 +18,9 @@ diff --git a/options.c b/options.c int basis_dir_cnt = 0; char *dest_option = NULL; -+#define MAX_REMOTE_ARGS (MAX_SERVER_ARGS/2) ++static int remote_option_alloc = 0; +int remote_option_cnt = 0; -+const char *remote_options[MAX_SERVER_ARGS+1] = { "ARG0" }; ++const char **remote_options = NULL; + int verbose = 0; int quiet = 0; @@ -41,7 +41,7 @@ diff --git a/options.c b/options.c {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 }, {"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 }, {"server", 0, POPT_ARG_NONE, 0, OPT_SERVER, 0, 0 }, -@@ -1140,6 +1146,20 @@ int parse_arguments(int *argc_p, const char ***argv_p) +@@ -1140,6 +1146,26 @@ int parse_arguments(int *argc_p, const char ***argv_p) } break; @@ -52,17 +52,23 @@ diff --git a/options.c b/options.c + "Remote option must start with a dash: %s\n", arg); + return 0; + } -+ if (remote_option_cnt >= MAX_REMOTE_ARGS) { -+ rprintf(FERROR, "too many remote options specified.\n"); -+ exit_cleanup(RERR_SYNTAX); ++ if (remote_option_cnt+3 > remote_option_alloc) { ++ remote_option_alloc += 16; ++ remote_options = realloc_array(remote_options, ++ const char *, remote_option_alloc); ++ if (!remote_options) ++ out_of_memory("parse_arguments"); ++ if (!remote_option_cnt) ++ remote_options[0] = "ARG0"; + } + remote_options[++remote_option_cnt] = arg; ++ remote_options[remote_option_cnt+1] = NULL; + break; + case OPT_WRITE_BATCH: /* batch_name is already set */ write_batch = 1; -@@ -1826,6 +1846,11 @@ void server_options(char **args, int *argc_p) +@@ -1826,6 +1852,11 @@ void server_options(char **args, int *argc_p) #endif argstr[x] = '\0'; @@ -74,7 +80,7 @@ diff --git a/options.c b/options.c args[ac++] = argstr; #ifdef ICONV_OPTION -@@ -2048,6 +2073,21 @@ void server_options(char **args, int *argc_p) +@@ -2048,6 +2079,21 @@ void server_options(char **args, int *argc_p) else if (remove_source_files) args[ac++] = "--remove-sent-files"; @@ -99,29 +105,19 @@ diff --git a/options.c b/options.c diff --git a/pipe.c b/pipe.c --- a/pipe.c +++ b/pipe.c -@@ -22,12 +22,15 @@ - - #include "rsync.h" - -+extern int am_root; - extern int am_sender; - extern int am_server; - extern int blocking_io; +@@ -28,6 +28,8 @@ extern int blocking_io; extern int filesfrom_fd; extern mode_t orig_umask; extern char *logfile_name; +extern int remote_option_cnt; -+extern const char *remote_options[]; ++extern const char **remote_options; extern struct chmod_mode_struct *chmod_modes; /** -@@ -139,6 +142,18 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out, +@@ -139,6 +141,15 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out, logfile_close(); } -+ if (am_root < 0) -+ am_root = 0; -+ + if (remote_option_cnt) { + int rc = remote_option_cnt + 1; + const char **rv = remote_options; @@ -145,7 +141,7 @@ diff --git a/rsync.yo b/rsync.yo --out-format=FORMAT output updates using the specified FORMAT --log-file=FILE log what we're doing to the specified FILE --log-file-format=FMT log updates using the specified FMT -@@ -1020,16 +1021,13 @@ This is a good way to backup data without using a super-user, and to store +@@ -1020,16 +1021,16 @@ This is a good way to backup data without using a super-user, and to store ACLs from incompatible systems. The bf(--fake-super) option only affects the side where the option is used. @@ -162,12 +158,15 @@ diff --git a/rsync.yo b/rsync.yo -"localhost" if you need to avoid this, possibly using the "lsh" shell -script (from the support directory) as a substitute for an actual remote -shell (see bf(--rsh)). -+For a local copy, this option affects only the source. Specify a -+bf(--remote-option) to affect the destination. ++For a local copy, this option affects both the source and the destination. ++If you wish a local copy to enable this option just for the destination ++files, specify bf(-M--fake-super). If you wish a local copy to enable ++this option just for the source files, combine bf(--fake-super) with ++bf(-M--super). This option is overridden by both bf(--super) and bf(--no-super). -@@ -1275,6 +1273,36 @@ machine for use with the bf(--relative) option. For instance: +@@ -1275,6 +1276,36 @@ machine for use with the bf(--relative) option. For instance: quote(tt( rsync -avR --rsync-path="cd /a/b && rsync" host:c/d /e/)) @@ -189,7 +188,7 @@ diff --git a/rsync.yo b/rsync.yo +and that will make it fail in a cryptic fashion. + +Note that it is best to use a separate bf(--remote-option) for each option you -+want to pass. This makes your useage compatible with the bf(--preserve-spaces) ++want to pass. This makes your useage compatible with the bf(--protect-args) +option. If that option is off, any spaces in your remote options will be split +by the remote shell unless you take steps to protect them. + @@ -204,7 +203,7 @@ diff --git a/rsync.yo b/rsync.yo dit(bf(-C, --cvs-exclude)) This is a useful shorthand for excluding a broad range of files that you often don't want to transfer between systems. It uses a similar algorithm to CVS to determine if -@@ -1746,7 +1774,7 @@ option if you wish to override this. +@@ -1746,7 +1777,7 @@ option if you wish to override this. Here's a example command that requests the remote side to log what is happening: @@ -213,27 +212,3 @@ diff --git a/rsync.yo b/rsync.yo This is very useful if you need to debug why a connection is closing unexpectedly. -diff --git a/testsuite/chown.test b/testsuite/chown.test ---- a/testsuite/chown.test -+++ b/testsuite/chown.test -@@ -16,7 +16,7 @@ - case $0 in - *fake*) - $RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests" -- RSYNC="$RSYNC --fake-super" -+ RSYNC="$RSYNC --fake-super -M--fake-super" - TLS_ARGS=--fake-super - case "`xattr 2>&1`" in - *--list:*) -diff --git a/testsuite/devices.test b/testsuite/devices.test ---- a/testsuite/devices.test -+++ b/testsuite/devices.test -@@ -17,7 +17,7 @@ outfile="$scratchdir/rsync.out" - case $0 in - *fake*) - $RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests" -- RSYNC="$RSYNC --fake-super" -+ RSYNC="$RSYNC --fake-super -M--fake-super" - TLS_ARGS=--fake-super - case "`xattr 2>&1`" in - *--list:*) diff --git a/slow-down.diff b/slow-down.diff index 6265396..1968278 100644 --- a/slow-down.diff +++ b/slow-down.diff @@ -25,7 +25,7 @@ diff --git a/flist.c b/flist.c extern struct stats stats; extern char *filesfrom_host; -@@ -1542,6 +1543,9 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, +@@ -1553,6 +1554,9 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, } send_file_name(f, flist, fbuf, NULL, flags, filter_level); diff --git a/slp.diff b/slp.diff index 9832370..8d0815c 100644 --- a/slp.diff +++ b/slp.diff @@ -180,7 +180,7 @@ diff --git a/options.c b/options.c diff --git a/rsync.h b/rsync.h --- a/rsync.h +++ b/rsync.h -@@ -190,6 +190,10 @@ +@@ -191,6 +191,10 @@ #define SIGNIFICANT_ITEM_FLAGS (~(\ ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE)) diff --git a/source-filter_dest-filter.diff b/source-filter_dest-filter.diff index e045b8e..cfd5dbc 100644 --- a/source-filter_dest-filter.diff +++ b/source-filter_dest-filter.diff @@ -314,7 +314,7 @@ diff --git a/receiver.c b/receiver.c diff --git a/rsync.h b/rsync.h --- a/rsync.h +++ b/rsync.h -@@ -134,6 +134,7 @@ +@@ -135,6 +135,7 @@ #define IOERR_DEL_LIMIT (1<<2) #define MAX_ARGS 1000 diff --git a/stdout.diff b/stdout.diff index 1ce8ab9..87e7a66 100644 --- a/stdout.diff +++ b/stdout.diff @@ -45,6 +45,6 @@ diff --git a/options.c b/options.c + setvbuf(stdout, NULL, _IOLBF, 0); + } + - if (human_readable && argc == 2) { + if (human_readable && argc == 2 && !am_server) { /* Allow the old meaning of 'h' (--help) on its own. */ usage(FINFO); diff --git a/usermap.diff b/usermap.diff index 425e288..f09797a 100644 --- a/usermap.diff +++ b/usermap.diff @@ -36,7 +36,7 @@ diff --git a/flist.c b/flist.c gid = match_gid(gid, &gid_flags); } } -@@ -2158,8 +2159,13 @@ struct file_list *recv_file_list(int f) +@@ -2166,8 +2167,13 @@ struct file_list *recv_file_list(int f) int dstart, flags; int64 start_read; -- 2.34.1